Compare commits

..
38 Commits
Author SHA1 Message Date
Sebastiaan Janssen 27ae938099 Bump to 8.18.2 2022-03-23 10:17:26 +01:00
Sebastiaan Janssen edb69eea36 Cherry pick change away from Umbraco TV from v9 2022-03-21 16:16:40 +01:00
30bb416ff8 Add missing null checks for redirect URLs (#12154)
* Fixes missing null checks as reported in #10066

* Fixed check for null or empty in NPoco where clause.

Co-authored-by: Andy Butland <abutland73@gmail.com>
2022-03-21 14:48:55 +01:00
Sebastiaan Janssen a9b8090d6b Bump version to 8.18.1 2022-03-16 16:49:16 +01:00
Anders BjernerandSebastiaan Janssen 76ecb295cc Fixed issue with TryConvertValueToCrlType method incorrectly enclosing string values in double quotes 2022-03-16 16:42:22 +01:00
Sebastiaan Janssen ce817551a5 Merge branch 'v8/contrib' into v8/dev 2022-03-07 11:13:13 +01:00
inetzoandGitHub 32cd9fed49 Make GridPropertyEditor dirty if a control is removed (#12097)
The currentForm.$setDirty(); was missing when removing an control from a grid.
2022-03-05 17:09:35 +00:00
Nikolaj GeisleandGitHub cabb91dbe1 Merge pull request #12058 from umbraco/v8/bugfix/history-cleanup-make-contenttype-dirty
V8: Fix history cleanup not making content type dirty
2022-03-02 12:22:38 +01:00
Nikolaj GeisleandGitHub 633bc8fd8a Merge pull request #12069 from umbraco/v8/bugfix/missing-information-on-saving-variants
V8: Fix missing EditedCultures and Name in content saving notifications
2022-03-02 11:06:40 +01:00
9de4cf4444 Update src/Umbraco.ModelsBuilder.Embedded/PureLiveModelFactory.cs
Co-authored-by: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com>
2022-03-02 10:45:28 +01:00
nikolajlauridsen ffe9a14664 Remove unused helper method 2022-03-02 09:58:30 +01:00
nikolajlauridsen 1fb4b905c2 Remove pointless assert 2022-03-02 09:58:03 +01:00
nikolajlauridsen 4b8a16af7c Add null check when mapping history cleanup 2022-03-02 09:25:31 +01:00
nikolajlauridsen f6c4af745f Remove no longer relevant unit tests 2022-03-02 08:32:14 +01:00
Bjarke Berg 6dd8cb496b Aligned IsDirty behavior of HsitoryCleanup with how PropertyGroups and types behave.. 2022-03-01 12:51:20 +01:00
Bjarke Berg 8d6394e8e3 Fixed other issues with isDirty, that was true even when no changes was done 2022-03-01 10:34:13 +01:00
159f92d6f8 V8: Fix missing site identifier (#12035)
* Add SiteIdentifierService

* Use SiteIdentifier service to create site identifier if it doesn't exist

* Use default timeout for telemetry request

* Use SiteIdentifierService in TelemetryIdentifierStep

* Send SiteId when requesting dashboard

* Make empty GUID an invalid site identifier

Co-authored-by: nikolajlauridsen <nel@umbraco.dk>
2022-02-28 14:11:59 +01:00
nikolajlauridsen 75f8c09e85 Map dirty cultures to EditedCultures on content before saving 2022-02-28 13:04:08 +01:00
nikolajlauridsen 62de668380 Set the name on the content when setting default culture variant name 2022-02-28 13:03:40 +01:00
Andy ButlandandGitHub 96349e4754 Extended check for locally installed LocalDb to include the most recent version 15. (#12031) 2022-02-27 18:10:31 +01:00
Bjarne FyrstenborgandSebastiaan Janssen 1ec98139c6 Media entry editor listview children (#12061)
(cherry picked from commit 6fd45f653c)

# Conflicts:
#	src/Umbraco.Web.UI.Client/src/common/services/mediapreview.service.js
2022-02-27 17:59:10 +01:00
Mole 7bb85c9ed6 Handle setting HistoryCleanup to null 2022-02-25 13:09:31 +01:00
Mole 25ac6b275e Remove ResetWereDirtyProperties override 2022-02-25 11:44:00 +01:00
Mole db8fe55d08 Remove dirty HistoryCleanup properties when HistoryCleanup is replaced 2022-02-25 11:30:34 +01:00
Mole 86fcb8e715 Ensure replacing the entire HistoryCleanup registers as dirty 2022-02-25 09:41:20 +01:00
Mole c85486b866 Fix tests 2022-02-25 09:39:35 +01:00
Mole 4e2302ab6e Remove overrides 2022-02-25 09:39:04 +01:00
Mole a87e7a12d0 Flow changed properties back to ContentType using PropertyChanged 2022-02-25 08:37:53 +01:00
nikolajlauridsen 2fc8f62195 Implement more overrides for BeingDirtyBase 2022-02-24 14:31:40 +01:00
nikolajlauridsen 586c4e8db3 Add tests for content type being dirty 2022-02-24 13:13:38 +01:00
nikolajlauridsen 5c663fd0f0 Override IsDirty and ResetDirtyProperties in ContentType
In order to call it in both HistoryCleanup and base.
2022-02-24 13:13:08 +01:00
nikolajlauridsen 4f89cb1a34 Make HistoryCleanup inherit from BeingDirtyBase and implement dirty properties 2022-02-24 13:12:02 +01:00
Bjarke BergandSebastiaan Janssen 424db16ab1 Fix issue with namespace in api docs 2022-02-24 12:54:44 +01:00
Sebastiaan Janssen e9be3dd4a5 Bump version to 8.18.0 2022-02-24 11:24:19 +01:00
Bjarke Berg 8ff1d49346 Added noop migration just to change state, so this database do not just directly to 9.3 when migrating 2022-02-17 14:09:26 +01:00
MoleandGitHub 1473e41a20 V8: Fix deleting file on external filesystem (#11998)
* Use IFileSystem to check if folder exists when deleting file

* Rename CanDeleteDirectory back to IsDirectory
2022-02-17 09:35:10 +01:00
Sebastiaan Janssen 2038898f4c Bump version to 8.18.0-rc2 2022-02-17 09:25:11 +01:00
Ronald BarendseandGitHub 40c08f81c4 Add support for readonly properties (#11730) 2022-02-16 11:42:34 +01:00
22475 changed files with 643073 additions and 1402762 deletions
-4
View File
@@ -1,4 +0,0 @@
**/*
!tests/Umbraco.Tests.Integration/bin/**
!tests/Umbraco.Tests.UnitTests/bin/**
**/node_modules
-94
View File
@@ -1,94 +0,0 @@
---
name: umb-bump-version
description: Bump the Umbraco CMS version across all required files. Use when the user asks to bump, update, or set the version number — e.g., "bump version to 17.3.4", "set version to 18.0.0-rc", "update version". Accepts the target version as an argument.
argument-hint: <version> (e.g., 17.3.4, 18.0.0-rc)
---
# Bump Version - Umbraco CMS
Updates the Umbraco CMS version string across all files that track it.
**Do NOT use AskUserQuestion if a version argument is provided. Only ask if `$ARGUMENTS` is empty or cannot be parsed as a version.**
## Arguments
- `$ARGUMENTS` - Required: the target version string (e.g., `17.3.4`, `18.0.0-rc`)
## Files to Update
The following 5 files must be updated with the new version:
| # | File | Field |
|---|------|-------|
| 1 | `version.json` | `"version"` |
| 2 | `src/Umbraco.Web.UI.Client/package.json` | `"version"` |
| 3 | `src/Umbraco.Web.UI.Client/package-lock.json` | top-level `"version"` AND `packages[""].version` |
| 4 | `tests/Umbraco.Tests.AcceptanceTest/package.json` | `"version"` |
| 5 | `tests/Umbraco.Tests.AcceptanceTest/package-lock.json` | top-level `"version"` AND `packages[""].version` |
**Note**: For major version bumps (e.g., 17.x to 18.x), `src/Umbraco.Web.UI.Login/package.json` has a caret-ranged dependency on `@umbraco-cms/backoffice` (e.g., `^17.2.0`) that will need manual updating. This skill does not handle that — major bumps involve many other changes beyond version strings.
## Instructions
### 1. Parse and Validate the Version
Extract the version from `$ARGUMENTS`. It must be a valid semver-like string (e.g., `17.3.4`, `18.0.0-rc`, `17.4.0-preview.1`). If no version is provided or it cannot be parsed, ask the user for the target version.
### 2. Read the Current Version
Read `version.json` and extract the current `"version"` value. If the current version already equals the target version, report that the version is already set and stop — do not edit, stage, or commit anything.
Otherwise, display both versions:
```
Bumping version: {current} -> {target}
```
### 3. Update All Files
Update each of the 5 files listed above, replacing the old version with the new version. For each file:
- **`version.json`**: Replace the `"version"` value.
- **`package.json` files**: Replace the `"version"` value (near the top of the file).
- **`package-lock.json` files**: Replace BOTH the top-level `"version"` value AND the `"version"` inside the `"packages": { "": { ... } }` block. These are always in the first ~10 lines of the file.
Use targeted edits — do NOT rewrite entire files. Be precise to avoid changing version strings in dependency entries.
### 4. Verify
After all edits, grep for the target version value across the 5 files to confirm all updates landed correctly:
```bash
grep -n "\"version\": \"{version}\"" version.json src/Umbraco.Web.UI.Client/package.json src/Umbraco.Web.UI.Client/package-lock.json tests/Umbraco.Tests.AcceptanceTest/package.json tests/Umbraco.Tests.AcceptanceTest/package-lock.json
```
Expect exactly 7 matches (one per `package.json` and `version.json`, two per `package-lock.json`).
### 5. Stage and Commit
Stage only the 5 changed files:
```bash
git add version.json src/Umbraco.Web.UI.Client/package.json src/Umbraco.Web.UI.Client/package-lock.json tests/Umbraco.Tests.AcceptanceTest/package.json tests/Umbraco.Tests.AcceptanceTest/package-lock.json
```
Then commit with the message `Bump version to {version}.` — replacing `{version}` with the target version:
```bash
git commit -m "Bump version to {version}."
```
### 6. Report
Output a summary:
```
Version bumped to {version} in:
- version.json
- src/Umbraco.Web.UI.Client/package.json
- src/Umbraco.Web.UI.Client/package-lock.json
- tests/Umbraco.Tests.AcceptanceTest/package.json
- tests/Umbraco.Tests.AcceptanceTest/package-lock.json
Changes staged and committed.
```
-135
View File
@@ -1,135 +0,0 @@
---
name: umb-release-notes
description: Improve a set of auto-generated GitHub release notes for an Umbraco CMS release. Cross-checks the notes against every PR carrying the release label, adds any that are missing, re-files every PR under the most appropriate category, and strips purely-internal entries. Use whenever the user asks to tidy up, improve, complete, or recategorize release notes for a given version, or mentions a release-notes text file plus a version number.
argument-hint: <version> <path-to-generated-notes-file>
---
# Umbraco CMS - Improve Release Notes
Takes a file of auto-generated GitHub release notes and produces an improved version that:
1. **Is complete** — every merged PR carrying the `release/<version>` label appears.
2. **Is well-categorized** — every PR sits under the most appropriate heading.
3. **Is free of noise** — purely-internal entries of no value to a reader are removed.
The result is written to a **new** file alongside the input, so the user can diff the two.
**Run autonomously.** Do NOT use `AskUserQuestion` once the required arguments (version and input file path) are available — only ask if one of them is missing from `$ARGUMENTS` and cannot be inferred (see Arguments). Beyond that, make the categorization calls yourself using the rules below; if a handful are genuinely borderline, place them anyway and note the borderline ones in your closing summary so the user can override.
## Arguments
`$ARGUMENTS` contains two values:
1. **Version** — e.g. `17.5.0`, `18.1.0`. The GitHub label to search is `release/<version>` (so version `17.5.0` → label `release/17.5.0`).
2. **Input file path** — full path to the text file holding the auto-generated notes (e.g. `C:\Temp\release-17.5.0-rc.md`).
If either is missing, ask the user once for the missing value, then proceed.
## Prerequisites
Run `gh auth status`. If it fails, tell the user to authenticate `gh` (e.g. `gh auth login`) and stop — the skill needs the GitHub CLI to query PRs. The repo is always `umbraco/Umbraco-CMS`.
## Procedure
### 1. Read the input notes
Read the input file. Note its structure — it is GitHub's generated format:
- A leading HTML comment (`<!-- Release notes generated ... -->`).
- A `## What's Changed` heading followed by `### <emoji> <Category>` sub-headings, each with `* <title> by @<author> in <url>` bullets.
- A trailing `## New Contributors` section and a `**Full Changelog**: ...` line.
Extract the set of PR numbers already present (parse the `/pull/<number>` from each bullet). Preserve each existing bullet's **exact text** (title, author, URL) when you re-emit it — only its category placement may change.
### 2. Fetch every labelled PR
```bash
gh pr list --repo umbraco/Umbraco-CMS --label "release/<version>" --state closed --limit 1000 \
--json number,title,author,labels,mergedAt \
--jq '.[] | select(.mergedAt != null) | "\(.number)\t\(.author.login)\t\([.labels[].name] | join(", "))\t\(.title)"' | sort -n
```
This is the authoritative list of what the release *should* contain. Each row gives number, author, labels, title.
**Guard against silent truncation.** `gh pr list` caps at `--limit` without warning, so a large release could drop the overflow and the skill would still look "complete". Count the returned rows and compare against the limit:
```bash
gh pr list --repo umbraco/Umbraco-CMS --label "release/<version>" --state closed --limit 1000 --json number --jq 'length'
```
If this equals 1000, the limit was hit — raise `--limit` and re-fetch before continuing. Do **not** proceed on a truncated list.
### 3. Reconcile
- **Missing labelled PRs** (labelled but not in the input file): these must be **added**. Build a bullet as `* <title> by @<author> in https://github.com/umbraco/Umbraco-CMS/pull/<number>`.
- **Author handle.** `<author>` in the template is the raw `.author.login` value — the bullet supplies the leading `@`, so do not prepend another. `gh`'s `.author.login` already returns bot accounts with the `[bot]` suffix as part of the login — Dependabot comes back as `dependabot[bot]`, not `dependabot` or `app/dependabot` (the `app/` form only appears in git committer metadata and CODEOWNERS, never in `gh`'s JSON). So the login is already in the right shape; use it verbatim (e.g. `.author.login` of `dependabot[bot]` renders as `@dependabot[bot]`, matching what GitHub's generator wrote for the existing bullets). The only thing to guard against is accidentally stripping or altering the `[bot]` suffix.
- **PRs in the file but not labelled**: keep them. The generated notes span a commit range (see the `Full Changelog` compare link), so they legitimately include backports / earlier-version PRs that lack the current label. For any of these you need to categorize, fetch its labels with:
```bash
gh pr view <number> --repo umbraco/Umbraco-CMS --json number,title,labels \
--jq '"\(.number)\t\([.labels[].name] | join(", "))\t\(.title)"'
```
Do **not** invent or alter the `New Contributors` section — carry it over verbatim. You cannot reliably recompute first-time contributors, so leave it as the generator produced it (mention this in the summary).
### 4. Categorize every PR
Use exactly these headings, in this order. Omit any heading that ends up with no entries.
| Heading | What goes here | Primary signal |
|---|---|---|
| `### 🙌 Notable Changes` | **Don't recategorize existing entries.** Label-driven — but still add any missing PR carrying this label here. | label `category/notable` |
| `### 💥 Breaking Changes` | **Don't recategorize existing entries.** Label-driven — but still add any missing PR carrying this label here. | label `category/breaking` |
| `### 📦 Dependencies` | Dependency bumps | label `dependencies`; or dependabot author |
| `### 🚀 New Features` | New user- or developer-facing capability | label `type/feature` / `category/feature`; or title introduces/adds a genuinely new capability |
| `### 🚤 Performance` | Performance improvements | label `category/performance`; or `Performance:` title prefix |
| `### 🌈 Accessibility Improvements` | A11y improvements (labels, contrast, keyboard) | label `category/accessibility` / `accessibility`; or clear a11y intent (e.g. "improve contrast", "missing labels") |
| `### 🐛 Bug Fixes` | Fixes to broken/incorrect behaviour | default for anything describing a fix |
| `### 🧪 Testing` | Test additions/changes only | label `category/test-automation` / `area/test`; or `E2E`/`QA`/"acceptance tests"/"unit test coverage"/"add tests" titles |
| `### 🛡️ Code Quality, Documentation and Refactoring` | Refactors, deprecations, API tidy-ups, XML/MD documentation, knowledge-base (`MD`) updates | label `category/refactor`; or titles about refactoring, deprecating, renaming, documenting, constants extraction, MD/CLAUDE.md content |
| `### 🧑‍💻 Developer Experience` | Things that improve the experience of developers building on or contributing to Umbraco — dev tooling, build/watch ergonomics, test mocks/harnesses, backoffice dev utilities | `Developer Experience` title prefix; dev tooling; mock/harness changes |
**Rules:**
- **Notable and Breaking are off-limits for recategorization** — never move a PR that is *already in the input file* into or out of these sections; they are driven purely by their labels and the generator placed them correctly. This does **not** exempt them from completeness: a PR discovered as missing in step 3 that carries `category/notable` or `category/breaking` must still be **added** under the matching section.
- Label signals beat title wording, except a `Performance:`/`Developer Experience:` title prefix is decisive for its section.
- A PR with both `type/feature` and `category/refactor` whose title clearly describes a refactor (e.g. "swap relative imports", "re-export type") belongs under Code Quality, not New Features.
- "Add ... tests"/"unit test coverage" → Testing, even if it also touches docs. If a PR adds XML documentation *and* tests, lead with where the title's emphasis lies (documentation → Code Quality; test coverage → Testing).
- When a PR is genuinely 50/50, pick the more reader-useful heading and list it in your closing summary as borderline.
### 5. Remove purely-internal noise
Drop entries that have **no value to anyone reading release notes** — pure repository plumbing with no shipped impact. Examples:
- Branch/merge maintenance ("Fix main branch after merge issue").
- CI/pipeline fixes that don't change the product.
- Reverts of changes that never shipped in a release.
**Keep** anything that ships in the product or genuinely helps developers building on Umbraco — that includes documentation/MD updates, dev tooling, and test mocks (those go to Code Quality or Developer Experience, they are *not* noise). When unsure whether something is noise, keep it and flag it in the summary rather than silently dropping it. List every removal in your closing summary.
### 6. Write the output
Write to a new file in the **same folder** as the input, named by appending ` - with updates` before the extension:
- Input `C:\Temp\release-17.5.0-rc.md` → Output `C:\Temp\release-17.5.0-rc - with updates.md`
Preserve the leading HTML comment, the `## What's Changed` heading, the `## New Contributors` section, and the `**Full Changelog**` line exactly. Only the `### <category>` groupings and their bullets change.
### 7. Report
Give a concise summary:
- Count of PRs added (with their numbers), and which categories they landed in.
- Notable recategorizations (PRs moved out of the catch-all Bug Fixes into Features/Performance/Testing/etc.).
- Every entry removed, with the one-line reason.
- Any borderline calls the user may want to override.
- The output file path.
## Verification
Before reporting done, confirm:
- Every PR number from step 2 is present in the output (except any you deliberately removed in step 5 — and those must be in the removal list).
- No PR appears under more than one heading.
- Notable and Breaking sections are byte-for-byte unchanged from the input.
- The header comment, New Contributors, and Full Changelog lines are intact.
-251
View File
@@ -1,251 +0,0 @@
---
name: umb-review
description: Automated PR code review for Umbraco CMS. Analyzes changed files for intent, impact on consumers, breaking changes, architecture compliance, and code quality. Non-interactive — outputs a full structured review. Use this skill whenever the user asks to review a branch, review a PR, check their changes for issues, analyze a diff, or validate breaking change patterns — even if they don't say "review" explicitly. Does NOT apply to writing new code, fixing bugs, refactoring, explaining architecture, writing tests, or reviewing documentation content.
argument-hint: <target-branch>
---
# PR Review - Umbraco CMS
Automated, non-interactive PR code review. Analyzes changed files for intent, impact on consumers, breaking changes, architecture compliance, and code quality.
**Do NOT use AskUserQuestion at any point. This skill runs fully autonomously.**
## Arguments
- `$ARGUMENTS` - Optional: target branch to diff against (auto-detected from PR, falls back to `origin/main`)
## Instructions
### 0. Verify GH CLI is Available
Run `gh auth status`. If it fails, read `references/gh-cli-setup.md` and present the setup instructions to the user. Do not proceed with the review.
### 1. Resolve Target Branch
Determine the target branch for comparison using this priority order:
1. **Explicit argument**: If `$ARGUMENTS` is provided and non-empty, use it as the target branch
2. **PR target branch**: If no argument, run `gh pr view --json baseRefName --jq '.baseRefName'` to detect the target branch of the current branch's open PR. If a PR exists, use `origin/{baseRefName}` as the target branch.
3. **Fallback**: If no argument and no PR found (command fails or returns empty), default to `origin/main`
Store the resolved target branch for use in subsequent steps. Log which resolution method was used (e.g., "Target branch: `origin/v18/dev` (from PR #1234)").
### 2. Load Review Standards
#### 2a. Load coding preferences
Read the coding preferences and code review scoring criteria from:
- `references/coding-preferences.md` (relative to this skill file)
Parse and internalize all rules, conventions, scoring categories, and severity definitions. These are your review criteria.
#### 2b. Load area-specific documentation
Once the changed file list is known (after step 3a), determine which areas of the codebase are touched and load the relevant documentation. Execute this sub-step between 3a and 3b. This documentation takes precedence over sibling comparison for architectural and pattern validation.
**Resolution order for each changed file:**
1. **Find the nearest `CLAUDE.md`** — walk up from the changed file's directory toward the repository root. The first `CLAUDE.md` found is the area guide for that file. Read it.
2. **Read referenced docs** — if the `CLAUDE.md` references documentation files (e.g., a `docs/` directory), use the descriptions in the `CLAUDE.md` to determine which docs are relevant to the type of code being changed, and read those. If unsure, read all referenced docs — the cost of reading is low, the cost of missing a convention is high.
3. **Follow cross-references in loaded docs** — if a loaded doc references another doc as covering a complementary or related concern, and the changed files touch that concern, read the referenced doc too. Repeat until no new relevant cross-references remain.
4. **Check for applicable skills** — review the available skills list. If a skill exists for the type of code being changed, read the skill file to understand the expected patterns, structure, and conventions it enforces. Do NOT invoke the skill — just use it as a reference for what the correct implementation should look like.
**Store all loaded documentation** for use in step 4. These docs define the authoritative patterns and conventions that the review evaluates against.
### 3. Gather Changed Files
#### 3a. Collect file list, stats, and diff
Run these git commands (where `{target}` is the resolved target branch):
```bash
git diff {target}...HEAD --name-only --diff-filter=d # changed files (excluding deleted)
git diff {target}...HEAD --stat # line counts per file
git log {target}...HEAD --oneline # commit history
git diff {target}...HEAD # full diff (primary review source)
```
**If no changes found**: Output "No changes found between current branch and `{target}`. Nothing to review." and stop.
#### 3b. Filter out noise files
From the changed file list, classify each file as **noise** or **reviewable**.
**Noise files** (skip entirely — do not read, do not review):
| Pattern | Reason |
| ---------------------------------------------------- | ------------------------------- |
| `*.gen.ts`, `*.gen.cs` | Auto-generated API client code |
| `*.generated.cs`, `*.Designer.cs` (in `Migrations/`) | Auto-generated models/snapshots |
| `*/assets/lang/*.ts` (except `en.ts`) | Non-English translation files |
| `*/mocks/data/*.ts` | Test fixture data |
| `*/dist-cms/*`, `*/storybook-static/*` | Build output |
| `*/TEMP/InMemoryAuto/*` | Runtime-generated models |
| `package-lock.json` | Dependency lock file |
| `appsettings-schema.*.json` | Generated JSON schema |
Log the skip list: "Skipped {N} noise files: {comma-separated list of filenames}"
#### 3c. Read reviewable changed files
Read the full file for every reviewable changed file.
#### 3d. Track file counts
Keep track of these numbers for the review output in step 7: total changed files, noise files skipped, and reviewable files read. Also record: distinct production layers touched, distinct project directories, and total lines changed — these feed step 3e.
#### 3e. Assess PR complexity
Follow the procedure in `references/complexity-assessment.md`. Store the triggered dimensions and suggestions for step 7.
#### 3f. Classify PR scope
Classify the PR to determine which review steps are relevant:
| Classification | Condition | Effect |
| --------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| **Gen-only** | All reviewable files are `gen.ts` | Skip steps 5 and 6; step 4 reviews impact on other code only |
| **Docs-only** | All reviewable files are `.md` | Skip steps 5 and 6; step 4 reviews intent and readability only |
| **Test-only** | All reviewable files are in `tests/` | Skip steps 5 and 6; step 4 reviews intent, code quality, and test coverage only |
| **Config-only** | All reviewable files are `.csproj`, `.props`, `.json` config, or CI/build files | Skip step 5; step 6 checks dependency version changes only |
| **Standard** | Anything else | No skips — run all steps |
### 4. Raw Code Review
Review each changed file holistically. Think like a senior developer reading a colleague's PR. Note all findings without worrying about format or severity yet.
#### 4a. Read and reason about each file
For each changed file, reason about: What does this code do? Is it correct? What's missing — validation, error handling, notifications, cleanup, edge cases? Could this break anything for consumers?
#### 4b. Validate against documentation and patterns
Use a **docs-first** approach: classify the code by what it does, check it against documented conventions, and only fall back to sibling comparison when docs don't cover the pattern.
**Step 1 — Determine the correct approach from documentation, then check whether the PR matches**
A PR is a proposed solution, not the source of truth. This step has two parts that must happen in order — do not start part B until part A is complete.
**Part A — Before validating/judging the implementation**, determine what the correct approach is for each new class or file based on what it does. Use the documentation loaded in step 2b to identify the expected base classes, patterns, and conventions. Write down the expected approach. Classify based on what the code does, not based on what neighboring files look like.
**Part B — Now compare the PR's implementation** against the expected approach from Part A. If it deviates from the documented approach, flag it. If the documentation specifies reference examples, read those examples to verify the implementation matches.
**Pattern match is the leading finding.** If the documentation defines a pattern that fits what the code does, the first and most important finding is whether the code follows that pattern.
**Step 2 — Fall back to sibling comparison**
If the documentation does not cover the specific pattern, or for cross-cutting concerns not addressed in docs, fall back to sibling comparison:
1. **New method on existing class/interface**: Grep for the most similar existing method on the same class using `-A 80` to capture the full method body (e.g., `UpdateCurrentUserAsync` → grep for `UpdateAsync` in the same file with `-A 80`). Compare line by line for missing cross-cutting concerns: notifications/events, validation, scoping, authorization, error handling, audit logging.
2. **New TS class**: Grep for siblings by base class (`extends {BaseClass}`) or by interface (`implements {Interface}`) or by name suffix (e.g., `CurrentUserController` → grep for `UserController`). Compare for missing concerns.
3. **New CS class**: Grep for siblings by base class (`class {ClassName} : {BaseClass}`) or by interface (`class {ClassName} : {Interface}`) or by name suffix (e.g., `ManagementApiComposer` → grep for `ApiComposer`). Compare for missing concerns.
**Important:** Sibling comparison validates cross-cutting concerns, but it must not override documented conventions. If a sibling deviates from documented patterns, that sibling is wrong — do not copy its deviation.
Store your raw findings — they feed into step 7.
### 5. Impact Analysis
**Skip this step if PR scope is docs-only, test-only, or config-only.**
Follow the procedure in `references/impact-analysis.md`.
### 6. Breaking Changes Check
**Skip this step if PR scope is docs-only or test-only. If config-only, only check for dependency version changes that could break consumers.**
Follow the procedure in `references/breaking-changes.md`.
### 7. Consolidate and Output Review
Merge findings from step 4 (raw review), step 5 (impact analysis), and step 6 (breaking changes). For each finding, assign severity (Critical/Important/Suggestion) and verify it relates to changed code — not pre-existing issues. Before outputting, drop any finding about whitespace, blank lines, formatting, or comment wording. Then present the review in this exact format:
```markdown
## PR Review
**Target:** `{target_branch}` · **Based on commit:** `{head_sha}`
[If any skipped files, append: · **Skipped:** {skipped} files out of {total} total]
[If step 3f classification is not "Standard", append: · **Classified as:** {classification}]
[12 sentences: what this PR accomplishes , keep it as short as possible, only highlight the primary essence.]
- **Modified public API:** {changed existing interfaces/types/classes/methods}
[Omit bullet if none]
- **Affected implementations (outside this PR):** {interfaces/types/classes/methods using modified public API}
[Omit bullet if none]
- **Breaking changes:** {violations with specifics}
[Omit bullet if none]
- **Other changes:** {changes not listed above that an Umbraco user, plugin developer, or API consumer would notice — e.g., behavior changes, default value changes, error message changes, new configuration options, removed functionality. Exclude internal renames, formatting, and private implementation details.}
[Omit bullet if none]
[If step 3e triggered any dimensions, insert this block. Omit entirely if nothing triggered:]
> [!NOTE]
> **Complexity advisory** — This PR may benefit from splitting.
>
> - **{Dimension}:** {Explanation and concrete split suggestion from step 3e}
> [one bullet per triggered dimension]
>
> _This is an observation, not a blocker. The full review follows below._
---
### Critical
[Must fix before merge — security vulnerabilities, data loss, broken functionality, breaking changes without proper patterns]
- **`{file}:{line}`**: {problem} → {fix}
[Omit section if none]
### Important
[Should fix — performance issues, missing tests, architectural violations, pattern misuse]
- **`{file}:{line}`**: {observation} → {suggestion}
[Omit section if none]
### Suggestions
[Nice to have — readability, minor refactoring, alternative approaches]
- **`{file}:{line}`**: {detail}
[Omit section if none]
---
[One of:]
## Approved
This looks good to be merged as-is, but please do a manual sanity check and testing before merging.
## Approved with Suggestions for improvement
Good to go, but please carefully consider the importance of the suggestions.
## Request Changes
Critical and important issues must be addressed first.
## Needs re-work
This is in such a bad state that the feedback of this review is not sufficient to guide improvements, the PR cannot be approved.
```
**Guidelines for the review output:**
— When reporting information, be extremely concise and sacrifice grammar for sake of concision.
- Only review code that was changed in the diff — pre-existing issues are out of scope. Focus on what compilers and linters cannot catch: behavioral side-effects (e.g., a changed default alters runtime behavior for consumers), architectural violations (e.g., a new dependency breaks layering), breaking changes for external consumers of the public API, and security implications. Leave type errors, missing imports, and broken references to CI.
- Be specific — always reference file and line number
- Explain WHY something is an issue, not just WHAT, but avoid stating the obvious.
- For complex matters, provide concrete fix suggestions, including code snippets when helpful
- Keep it constructive — the goal is to help, not gatekeep
- Don't repeat the same finding for every occurrence — mention it once and note "same pattern in {other files}"
- Focus on substantive issues only. Do NOT flag purely cosmetic or stylistic concerns. Specifically, never flag: code formatting or whitespace, comment grammar or wording, redundant-but-harmless syntax (e.g., optional chaining after a truthiness check), code duplication that doesn't cause bugs, or HTML template cosmetics. The only exception is when a stylistic issue has a concrete impact on performance or rendering. Note: missing JSDoc/documentation on public or exported APIs is a substantive finding (per coding preferences), not a cosmetic one — flag it as a Suggestion.
- For breaking changes, reference the specific pattern from the CLAUDE.md that should be applied
- Do not suggest changes that would themselves introduce breaking changes. If a suggestion would alter public API surface (e.g., changing return types, renaming public members), it is not appropriate for a PR targeting `main` within a major version. Only suggest non-breaking alternatives.
@@ -1,97 +0,0 @@
{
"skill_name": "umb-review",
"evals": [
{
"id": 0,
"name": "pr-22214-large-frontend-refactor",
"prompt": "Review the changes in PR #22214 (branch origin/pr/22214 targeting main). This is a large frontend refactor migrating create entity actions to use entityCreateOptionAction extensions, with deprecations.",
"expected_output": "A structured review that identifies frontend deprecation patterns, flags the large PR complexity, handles 75+ files correctly, checks for breaking changes in exported components, and produces the correct output format.",
"pr_number": 22214,
"pr_branch": "origin/pr/22214",
"base_branch": "origin/main",
"files": [],
"assertions": [
{"id": "deprecation-patterns-noted", "text": "Review identifies deprecation patterns (@deprecated, UmbDeprecation)"},
{"id": "frontend-breaking-change-awareness", "text": "Checks frontend-specific breaking changes (exports, custom elements) not just backend"},
{"id": "file-references-present", "text": "Findings reference specific files with line numbers"},
{"id": "no-false-critical-on-deprecations", "text": "Properly deprecated code is NOT flagged as Critical breaking change"},
{"id": "no-stylistic-nitpicks", "text": "Review does not flag purely cosmetic/stylistic issues (formatting, whitespace, naming conventions, comment grammar, code style preferences) unless they affect performance or rendering. Missing JSDoc on new public APIs is NOT a stylistic issue — it is a legitimate finding."},
{"id": "manifest-alias-rename-detected", "text": "Alias renames (CreateOptions → Create) flagged as Critical breaking change"},
{"id": "non-exported-deletions-dismissed", "text": "Deleted action classes NOT flagged as breaking (verified against package.json exports)"},
{"id": "noise-files-filtered", "text": "Does not review noise files (generated files, lock files, etc.)"},
{"id": "complexity-advisory-triggers", "text": "Review includes a complexity/split advisory for the large 75+ file scope"}
]
},
{
"id": 1,
"name": "pr-21672-small-frontend-bugfix",
"prompt": "Review the changes in PR #21672 (branch origin/pr/21672 targeting main). This is a small 4-file frontend bugfix implementing tab validation badges in the block editor.",
"expected_output": "A clean review that correctly identifies this as a small focused bugfix, avoids false positives, and either approves or approves with minor suggestions.",
"pr_number": 21672,
"pr_branch": "origin/pr/21672",
"base_branch": "origin/main",
"files": [],
"assertions": [
{"id": "complexity-advisory-absent", "text": "Review does NOT include a complexity/split advisory"},
{"id": "no-false-breaking-changes", "text": "Review does not flag breaking changes"},
{"id": "proportionate-verdict", "text": "Verdict is 'Request Changes'"},
{"id": "concise-review", "text": "Review output is under 200 lines"},
{"id": "no-stylistic-nitpicks", "text": "Review does not flag purely cosmetic/stylistic issues (formatting, whitespace, naming conventions, comment grammar, code style preferences) unless they affect performance or rendering. Missing JSDoc on new public APIs is NOT a stylistic issue — it is a legitimate finding."}
]
},
{
"id": 2,
"name": "pr-22217-small-backend-webhook",
"prompt": "Review the changes in PR #22217 (branch origin/pr/22217 targeting v18/dev). This is a tiny 3-file backend change to the default webhook payload type.",
"expected_output": "A concise review that correctly resolves v18/dev as target branch, handles the small change proportionately, and considers the behavioral impact of changing a default value.",
"pr_number": 22217,
"pr_branch": "origin/pr/22217",
"base_branch": "origin/v18/dev",
"files": [],
"assertions": [
{"id": "correct-target-branch", "text": "Review references 'v18/dev' as the target branch (not 'main')"},
{"id": "default-value-change-noted", "text": "Review discusses the behavioral impact of changing the default payload type"},
{"id": "proportionate-review", "text": "Review output is under 150 lines"},
{"id": "no-stylistic-nitpicks", "text": "Review does not flag purely cosmetic/stylistic issues (formatting, whitespace, naming conventions, comment grammar, code style preferences) unless they affect performance or rendering. Missing JSDoc on new public APIs is NOT a stylistic issue — it is a legitimate finding."},
{"id": "ignores-preexisting-issues", "text": "Does NOT flag the ~30 builder extension methods with Legacy defaults (pre-existing, not changed in the PR)"},
{"id": "side-effect-detection", "text": "Flags stale WebhookSettings.cs docs as a side-effect of the constant value change"},
{"id": "consumer-identification", "text": "Identifies affected consumers outside the PR (WebhookSettings, UmbracoBuilder, or WebhookEventCollectionBuilderExtensions)"}
]
},
{
"id": 3,
"name": "pr-22268-frontend-feature-workspace-modal",
"prompt": "Review the changes in PR #22268 (branch origin/pr/22268 targeting main). This is a 29-file frontend feature adding a current user workspace modal.",
"expected_output": "A review of a medium-sized new feature PR. Should assess the new code for architectural compliance, check for breaking changes (new exports, custom elements), and evaluate code quality without flagging pre-existing issues.",
"pr_number": 22268,
"pr_branch": "origin/pr/22268",
"base_branch": "origin/main",
"files": [],
"assertions": [
{"id": "complexity-advisory-triggers", "text": "Review includes a complexity/split advisory (3 layers: Core, API, Frontend across 27+ files)"},
{"id": "breaking-changes-on-interface-additions", "text": "Flags new interface methods without default implementations as breaking changes (Pattern 3)"},
{"id": "no-stylistic-nitpicks", "text": "Review does not flag purely cosmetic/stylistic issues unless they affect performance or rendering. Missing JSDoc on new public APIs is NOT a stylistic issue — it is a legitimate finding."},
{"id": "diff-scoped", "text": "All findings reference code that was changed in the diff, not pre-existing issues"},
{"id": "new-feature-assessed", "text": "Review assesses the new feature's architecture, patterns, or integration approach — not just absence of bugs"},
{"id": "no-false-notification-finding", "text": "Review does NOT flag UpdateCurrentUserAsync as missing UserSavingNotification/UserSavedNotification — the sibling UpdateAsync also does not publish these notifications, so flagging their absence would be a false positive"}
]
},
{
"id": 4,
"name": "pr-22215-frontend-architecture-violation",
"prompt": "Review the changes in PR #22215 (branch origin/pr/22215 targeting main). This is a 2-file frontend feature adding user management to the user group workspace.",
"expected_output": "A review that catches the architecture violation: the workspace context directly imports and calls UserService and UserGroupService (generated API clients) instead of going through a repository. In the Umbraco backoffice, workspace contexts access data via repositories, not by calling API services directly. The review should flag this as a significant architecture issue and request changes.",
"pr_number": 22215,
"pr_branch": "origin/pr/22215",
"base_branch": "origin/main",
"files": [],
"assertions": [
{"id": "service-bypass-detected", "text": "Review flags that the workspace context directly imports/calls UserService or UserGroupService instead of using a repository"},
{"id": "repository-pattern-recommended", "text": "Review recommends using the repository pattern (going through a repository/data-source layer) rather than calling API services directly from the workspace context"},
{"id": "verdict-request-changes", "text": "Verdict is 'Request Changes' (the architecture violation warrants requesting changes, not just approving with suggestions)"},
{"id": "no-stylistic-nitpicks", "text": "Review does not flag purely cosmetic/stylistic issues (formatting, whitespace, naming conventions, comment grammar, code style preferences) unless they affect performance or rendering. Missing JSDoc on new public APIs is NOT a stylistic issue — it is a legitimate finding."},
{"id": "no-false-breaking-changes", "text": "Review does not flag breaking changes (this PR only adds new code, no public API is removed or modified)"}
]
}
]
}
@@ -1,249 +0,0 @@
# Breaking Changes Reference
This document describes how to detect and validate breaking changes during PR review. It covers both backend (.NET) and frontend (TypeScript/Lit) patterns.
---
## Version Detection
**Always read `version.json`** at the repository root to determine the current major version. This drives the obsolete removal target calculation:
- Current major version: read from `version.json``version` field (e.g., `"17.4.0-rc"` → major version `17`)
- Obsolete removal target: `current + 2` (e.g., if current is 17, removal is scheduled for Umbraco 19)
- Format: `[Obsolete("... Scheduled for removal in Umbraco {current+2}.")]`
---
## Backend (.NET) Breaking Changes
### What Constitutes a Breaking Change
Any of these on a `public` or `protected` member:
- Removing or renaming a class, interface, struct, record, or enum
- Removing or renaming a method, property, or field
- Changing a method signature (parameters, return type)
- Adding required parameters to an existing method
- Adding methods to a public interface (without default implementation)
- Changing a constructor signature on a public class
- Removing or changing enum values
- Changing type hierarchy (base class, implemented interfaces)
### Pattern 1: Obsolete Constructor + StaticServiceProvider
When a public class needs new dependencies, the existing constructor must be preserved.
**Correct pattern:**
```csharp
[Obsolete("Please use the constructor with all parameters. Scheduled for removal in Umbraco 19.")]
public MyService(IDependencyA depA)
: this(
depA,
StaticServiceProvider.Instance.GetRequiredService<IDependencyB>())
{
}
public MyService(IDependencyA depA, IDependencyB depB)
{
_depA = depA;
_depB = depB;
}
```
**Validation checklist:**
- [ ] Old constructor has `[Obsolete]` attribute with correct removal version
- [ ] Old constructor calls new constructor via `: this(...)`
- [ ] `StaticServiceProvider.Instance.GetRequiredService<T>()` used for new params only
- [ ] DI registration uses the NEW constructor (old is for external consumers only)
- [ ] Removal version is `{current_major + 2}`
**Common mistakes to flag:**
- Removing the old constructor entirely (breaking change!)
- Old constructor NOT calling new constructor (code duplication)
- Wrong removal version in `[Obsolete]`
- Missing `StaticServiceProvider` resolution for new dependencies
- DI registration still using the old constructor
### Pattern 2: Obsolete Method + New Overload
When a method signature needs to change, add the new overload and obsolete the old.
**Correct pattern:**
```csharp
[Obsolete("Use the overload taking all parameters. Scheduled for removal in Umbraco 19.")]
public void DoThing(string name)
=> DoThing(name, extraParam: null);
public void DoThing(string name, string? extraParam)
{
// Real implementation here
}
```
**Validation checklist:**
- [ ] Old method has `[Obsolete]` attribute with correct removal version
- [ ] Old method calls new method, providing defaults for new parameters
- [ ] All internal callers updated to use the new method
- [ ] No internal code references the obsolete method (except the delegation)
### Pattern 3: Default Interface Implementation
When adding methods to a public interface, provide a default implementation.
**Correct pattern:**
```csharp
public interface IMyService
{
void ExistingMethod();
// New method with default implementation
void NewMethod(string param)
=> ExistingMethod(); // delegate to existing if possible
}
```
**Strategies for defaults (in order of preference):**
1. Use existing interface methods to satisfy the contract
2. Return a sensible default (empty collection, null, etc.)
3. Throw `NotImplementedException` if no reasonable default exists
**Validation checklist:**
- [ ] New interface method has a default implementation
- [ ] TODO comment present: `// TODO (V{next-major}): Remove the default implementation when {obsolete method} is removed.`
- [ ] Default implementation is functionally correct (even if not optimal)
- [ ] If `StaticServiceProvider` is used in default impl, noted as temporary
### Obsolete Attribute Validation
For any `[Obsolete]` attribute found in changed code:
1. **Format**: Must contain `"Scheduled for removal in Umbraco {version}."`
2. **Version**: Must be `current_major + 2` (read from `version.json`)
3. **Pragma**: Where obsolete members must call each other, `#pragma warning disable CS0618` / `#pragma warning restore CS0618` must be present
### Internal Caller Check
After finding obsolete patterns, verify:
- Search the codebase for usages of the obsolete member
- **No internal code** (inside `src/`) should reference obsolete members
- Only the obsolete member's own delegation (calling the new version) is acceptable
- External consumers (outside the repo) get the deprecation period to migrate
---
## Frontend (TypeScript/Lit) Breaking Changes
The backoffice is published as `@umbraco-cms/backoffice` with 140+ named exports. Plugin developers depend on this public API surface.
**Critical frontend rule (does not apply to backend .NET where `public`/`protected` visibility determines the API surface): only symbols reachable through the `package.json` `exports` field are public API.** Anything not exported — whether classes, functions, constants, types, or entire files — is an internal implementation detail, even if other internal code imports it. Removing or changing unexported frontend symbols is not a breaking change. Before flagging a frontend deletion or rename as breaking, verify the symbol is reachable via `package.json` exports. If it is not, do not flag it.
### Custom Elements (Web Components)
**Breaking changes:**
- Renaming or removing a registered custom element tag (`umb-*`)
- Removing elements from `HTMLElementTagNameMap`
- Removing or changing `@property()` decorated fields on exported components
- Removing event emissions (checked via `this.dispatchEvent`)
- Removing CSS custom properties (`@cssprop` in JSDoc)
- Removing CSS parts (`@csspart` in JSDoc)
**How to detect:**
- Check diff for removed `@customElement('umb-...')` decorators
- Check diff for removed `@property()` fields on exported components
- Check diff for removed entries in `HTMLElementTagNameMap` declarations
### Exported Types/Interfaces
**Breaking changes:**
- Removing exports from `package.json` `exports` field
- Changing the shape of exported interfaces (removing properties, changing types)
- Renaming exported types (consumers import by name)
- Removing union type members
- Changing generic type parameter constraints
**How to detect:**
- Check if `package.json` `exports` field is modified
- Check diff for removed `export` statements
- Check diff for changed interface/type shapes
### Manifest/Extension System
**Breaking changes:**
- Renaming a manifest `alias` value — plugin developers reference aliases by string in conditions, overwrites, and extension registry lookups. Alias renames are not caught by the compiler since they are string-based. A renamed alias silently breaks any plugin that references the old string.
- Removing support for a manifest `type` that plugins use
- Changing manifest `alias` resolution or validation
- Removing or renaming manifest `kind` types
- Changing extension bundle structure
**How to detect:**
- **Alias renames**: Compare `alias:` values in manifest files before and after. Changed alias strings are Critical — the old alias should be preserved as a deprecated entry.
- Search for changes to manifest type definitions
- Check for removed or renamed manifest kinds
### Context API
**Breaking changes:**
- Removing context tokens from exports
- Changing the shape of data provided by a context
- Removing context provider/consumer mechanisms
**How to detect:**
- Check for removed context token exports
- Check for changes to context provider classes
### Controllers/Lifecycle
**Breaking changes:**
- Changing controller base class inheritance requirements
- Removing controller lifecycle hooks
- Breaking cleanup mechanisms in `disconnectedCallback()`
### Observable/State
**Breaking changes:**
- Removing observable properties from the public API
- Changing observable emission patterns
### npm Publishing
**Breaking changes:**
- Changing version constraints that exclude previously-supported versions
- Adding incompatible peer dependency constraints
**How to detect:**
- Check if `package.json` `peerDependencies` or `dependencies` changed
- Verify version ranges are not narrowed
---
## Reporting Breaking Changes
When a breaking change is detected, report:
1. **What**: The specific change and which public symbol is affected
2. **Pattern**: Which mitigation pattern should be applied (Pattern 1, 2, or 3 for backend)
3. **Severity**: Critical (no mitigation present) or Important (mitigation present but incorrect)
4. **Fix**: Concrete code suggestion showing the correct pattern
If no breaking changes are detected, state: "No breaking changes detected."
@@ -1,168 +0,0 @@
# Coding Preferences & Review Criteria
These are the coding preferences and code review standards used by the review skill. They define what the review evaluates against.
---
## Testing
- **Always create blackbox tests** for new/changed code
- Choose the appropriate test level:
- **Unit tests** for isolated logic
- **Integration tests** for application services/use cases
- **E2E tests** for API endpoints
### Test Class Naming
- Test classes must be postfixed with `Tests` (e.g., `OrderServiceTests`)
- One test class per class under test
### Test Method Naming
**C# tests**: Use the `Can_`/`Cannot_` pattern with PascalCase underscore-separated words:
- `Can_Schedule_Publish_Invariant`
- `Cannot_Delete_Non_Existing`
- `Can_Schedule_Publish_Single_Culture`
Large test classes are split into partial files by method: `ContentServiceTests.Delete.cs`, `ContentServiceTests.Publish.cs`.
**TypeScript tests**: Use BDD-style `it()` with natural language descriptions:
- `it('should not allow the returned value to be lower than min')`
- `it('converts string to camelCase')`
### Unit Tests
- Optional, but must be blackbox tests so refactoring does not break tests
### Integration Tests
- Every use case / application service must have integration tests
- Tests run against real database (containerized or similar)
- Test the full flow from application layer through infrastructure
### E2E Tests
- Every API endpoint must have E2E tests
- Test realistic scenarios including error cases
---
## Trade-offs
When making decisions, prioritize:
- **Readability** over cleverness
- **Flexibility** over rigidity
- Explain trade-offs when deviating from these defaults
---
## Breaking Changes
- Communicate breaking changes at the **OpenAPI/openapi.json level**
- Clearly document what changed and the migration path
---
## Documentation
- **Document all public or exported types** (classes, interfaces, types, methods, properties)
- Keep documentation in sync with code changes
- Add **JS Docs** on all public frontend APIs (classes, methods, properties)
- Focus on "why" and usage, not restating the obvious
---
## Dependencies
- Use what's available in the codebase, unless there is no good choice
- **Flag new dependencies** for review — new packages should be justified
- Prefer well-maintained, widely-used packages
---
## Error Messages & Logging
- **User-facing errors**: Clear, friendly, actionable
- **Log messages**: Technical, detailed, with context
- Include correlation IDs and relevant data in logs
---
## Security
- **Always check for security issues** using OWASP Top 10 as baseline
- Flag potential vulnerabilities immediately
- Suggest secure alternatives when spotting risky patterns
- Apply principle of least privilege
---
## Immutability
- Prefer **immutability** by default
- Allow internal properties to be mutated, as long as they are not direct references coming from the outside
---
## Nullability
- **TypeScript / JavaScript**
- Prefer `undefined` for optional/omitted values (e.g., optional parameters, props, and fields)
- Use `null` only when the domain model explicitly encodes "no value" or "not set" (e.g., `string | null` from APIs/DB), and be consistent with existing types
- Avoid mixing `null` and `undefined` for the same concept within the same model or API surface
- **C#**
- use nullable types (e.g., `string?`, `int?`) where absence is valid
- Prefer domain modeling (value objects, options/results, empty collections) over `null` where appropriate, but respect existing conventions in the codebase
---
## C# Specific
- use Notification pattern (not C# events), Composer pattern (DI registration), Scoping with `Complete()`, Attempt pattern for operation results.
---
## Architecture
- Follow **Clean Architecture** principles
- **Fail-fast** principle: detect and report errors as early as possible
- Within the established layered architecture (Core/Infrastructure/Web/API), organize code by feature inside each layer where practical, while preserving dependency direction
- One class per file
- Avoid N+1 queries
- Profile before optimizing non-critical paths
### Type Hierarchy Consistency
When parallel model types have inconsistent relationships to a shared base type:
**TypeScript**: manipulations via `Omit`, `Pick`, intersection overrides, or workarounds like `as unknown as` / double-casts to bridge type mismatches.
**C#**: hiding base members with `new` to change types, explicit interface implementations to mask mismatches, or downcasting base return types in derived classes.
- **Do NOT suggest** the PR code should deviate from its base type to match a sibling that already deviates. Copying the deviation spreads the problem.
- **Do flag** the architectural inconsistency: parallel models should share a compatible base contract. The model that manipulates or deviates from the base type is the one that needs attention — not the one that extends it correctly.
- **Frame the suggestion** as: "These related models have inconsistent type hierarchies. `{deviating type}` manipulates the base contract of `{base type}`, which forces shared consumers like `{shared utility}` to require a shape that conforming subtypes can't satisfy."
---
## Code Style
- Follow standard naming conventions for the language (C# or JS/TS)
- Keep components small and focused on a single responsibility
- Prefer early returns
- Small functions
- No nested ternaries
---
## Severity Levels
| Severity | Meaning |
|----------|---------|
| **Critical** | Must fix before merge — security vulnerabilities, data loss risks, broken functionality |
| **Important** | Should fix — performance issues, missing tests, architectural violations |
| **Suggestion** | Nice to have — readability, minor refactoring, alternative approaches |
@@ -1,33 +0,0 @@
# PR Complexity Assessment
Evaluate whether the PR's scope suggests it should be split. This assessment is **informational only** — it never blocks or shortens the review.
## Always check: Formatting mixed with logic
This check applies to every PR regardless of size or scope.
Run both commands and compare per-file line counts:
```bash
git diff {target}...HEAD --stat
git diff {target}...HEAD --stat --ignore-all-space
```
For any file where the whitespace-ignored diff is less than **half** the full diff size (and the full diff is over 50 lines), that file has significant formatting changes mixed with logic. Flag it with a split suggestion: "File(s) {list} contain significant formatting changes mixed with logic. Consider a separate formatting-only commit or PR to keep the functional diff reviewable."
## Multi-project scope check
Skip this section entirely if ALL production files reside in a single project directory or if the PR is docs-only, test-only, dependency-bump-only, or rename-only.
Otherwise, flag any dimension that applies:
| Dimension | Condition | Suggestion |
|---|---|---|
| **Size** | 30+ files OR 1500+ lines, spanning 2+ projects | "If changes in {projectA} and {projectB} are independently functional, they could be separate PRs." |
| **Layer spread** | 3+ layers touched (Core/Infrastructure/Web/API/Frontend), 10+ files | "Consider splitting by layer — e.g., Core+Infrastructure first, then API/Frontend consumers." |
| **Mixed intent** | 2+ intent categories (new feature, bugfix, refactor, dependency update) with 15+ files or 3+ projects | "Consider extracting the {secondary intent} into a separate PR." |
Intent categories — detect from diff characteristics, not commit messages:
- **New feature**: new files or new `public`/`export` declarations
- **Bug fix**: small targeted edits, no new files (don't co-flag with new feature)
- **Refactor**: file renames, symbols moved but logic unchanged
- **Dependency update**: changes to `.csproj`, `Directory.Packages.props`, `package.json`
@@ -1,23 +0,0 @@
# GH CLI Setup Instructions
The GitHub CLI (`gh`) is required for this review skill to detect PR target branches.
## Installation
Install via Homebrew:
```
brew install gh
```
Or see https://cli.github.com/ for other installation methods.
## Authentication
After installing, authorize by running this in the terminal (use the `!` prefix in Claude Code):
```
! gh auth login
```
Follow the prompts to authenticate with your GitHub account.
@@ -1,153 +0,0 @@
# Impact Analysis Reference
This document describes how to perform impact analysis during PR review. The goal is to look beyond the diff to understand how changes affect consumers in other parts of the codebase.
---
## 1. Extract Changed Public Symbols
Scan the diff output for changes to public API surface:
### Backend (.NET)
Look for added, modified, or removed lines containing:
- `public class`, `public abstract class`, `public sealed class`
- `public interface`
- `public record`, `public struct`, `public enum`
- `public` or `protected` methods, properties, fields
- `public static` members
- Constructor signatures on public types
### Frontend (TypeScript/Lit)
Look for changes to:
- `export class`, `export interface`, `export type`, `export enum`
- `export function`, `export const`
- `@property()` decorated fields on exported components
- `@customElement()` registrations
- Entries in `package.json` `exports` field
Collect a list of all changed public symbol names (type names, method names, property names).
---
## 2. Search for Consumers
For each changed public symbol, search the `src/` directory for usages **outside the changed file itself**.
### Grep Strategy
Use the Grep tool with these settings:
```
pattern: {symbol name}
path: src/
output_mode: files_with_matches
head_limit: 20
```
Use `head_limit: 20` to avoid overwhelming results — if there are more than 20 consumers, note "20+ consumers found" and list the first 20.
### What to Search For
For each changed type/method, search for:
- **Type references**: class name, interface name (e.g., `IContentService`)
- **Method calls**: method name in context (e.g., `\.GetById\(` for a method rename)
- **Constructor usage**: `new TypeName(`
- **DI registrations**: `.AddSingleton<IType, Type>`, `.AddScoped<`, `.AddTransient<`
- **Notification handlers**: if a notification type changed, search for `INotificationHandler<NotificationTypeName>` and `INotificationAsyncHandler<NotificationTypeName>`
- **Interface implementations**: if an interface changed, search for `: IInterfaceName` or `IInterfaceName,`
### Excluding the Changed File
When reporting consumers, exclude files that are part of the PR's changes (they're already being reviewed). The interesting consumers are those **outside** the PR that may be affected.
---
## 3. Check Dependency Flow Direction
The Umbraco architecture enforces strict unidirectional dependencies:
```
Api.Management / Api.Delivery (depend on Api.Common)
Api.Common (depends on Web.Common)
Web.Common (depends on Infrastructure)
Infrastructure (depends on Core)
Core (no dependencies)
```
### Layer Mapping
Map each changed file to its architectural layer:
| Path prefix | Layer |
|---|---|
| `src/Umbraco.Core/` | Core |
| `src/Umbraco.Infrastructure/` | Infrastructure |
| `src/Umbraco.PublishedCache.*` | Infrastructure |
| `src/Umbraco.Examine.Lucene/` | Infrastructure |
| `src/Umbraco.Cms.Persistence.*` | Infrastructure |
| `src/Umbraco.Web.Common/` | Web |
| `src/Umbraco.Web.UI/` | Web (Application) |
| `src/Umbraco.Web.Website/` | Web |
| `src/Umbraco.Cms.Api.Common/` | API |
| `src/Umbraco.Cms.Api.Management/` | API |
| `src/Umbraco.Cms.Api.Delivery/` | API |
| `src/Umbraco.Web.UI.Client/` | Frontend |
| `tests/` | Test |
### Violation Detection
Flag if a change introduces:
- **Core depending on Infrastructure**: Core file importing/referencing Infrastructure types
- **Core depending on Web/API**: Core file importing/referencing Web or API types
- **Infrastructure depending on Web/API**: Infrastructure file importing Web or API types
- **Cross-API dependencies**: Management API depending on Delivery API or vice versa
### How to Check
1. For each changed file, identify its layer
2. Read the file's `using` statements (C#) or `import` statements (TS)
3. Check if any imports reference a higher layer
4. Also check if new parameters or return types come from higher layers
---
## 4. Flag Cross-Project Risks
### High-Risk Patterns
These changes have high ripple potential:
- **Interface changes in Core** — all implementations in Infrastructure must be updated
- **Notification type changes** — all handlers across the codebase are affected
- **Base class changes** — all derived classes are affected
- **Composer changes** — can affect DI container and runtime behavior globally
- **Shared model/DTO changes** — can affect serialization, API contracts, and consumers
### What to Report
For each cross-project risk found, report:
1. **What changed**: The specific symbol and how it changed
2. **Who is affected**: List of consuming files/projects found via Grep
3. **Risk level**: Whether the consumers will break (compile error), behave differently (runtime), or are unaffected
4. **Recommendation**: Whether the PR should include updates to affected consumers
---
## 5. Performance Notes
- Use `head_limit: 20` on all Grep searches to cap results
- Only search for symbols that actually changed (not every symbol in the file)
- For very common type names (e.g., `IScope`, `ILogger`), consider adding more context to the search pattern to reduce false positives
- Skip impact analysis for test files — they don't have external consumers
- Skip impact analysis for private/internal members — they can't have external consumers
-24
View File
@@ -1,24 +0,0 @@
# [Choice] .NET version: 6.0, 3.1, 6.0-bullseye, 3.1-bullseye, 6.0-focal, 3.1-focal
ARG VARIANT=6.0-bullseye
FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT}
# [Choice] Node.js version: none, lts/*, 18, 16, 14
ARG NODE_VERSION="none"
RUN if [ "${NODE_VERSION}" != "none" ]; then su vscode -c "umask 0002 && . /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"; fi
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment this line to install global node packages.
# RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g <your-package-here>" 2>&1
# Following added by Warren...
# Sets the global user for npm as 'root' due to some permission errors for gulp-imagemin creating binaries
# https://stackoverflow.com/a/45505787
#
# Needing to set unsafe-perm as root is the user setup
# https://docs.npmjs.com/cli/v6/using-npm/config#unsafe-perm
# Default: false if running as root, true otherwise (we are ROOT)
#RUN npm -g config set user vscode && npm -g config set unsafe-perm
-93
View File
@@ -1,93 +0,0 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/main/containers/dotnet
{
"name": "C# (.NET) Umbraco & SMTP4Dev",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
// Set *default* container specific settings.json values on container create.
"settings": {
"omnisharp.defaultLaunchSolution": "umbraco.sln",
"omnisharp.enableDecompilationSupport": true,
"omnisharp.enableRoslynAnalyzers": true
},
"features": {
// Workaround until the image is updated to include the latest version of .NET Core - .NET7
// https://github.com/devcontainers/templates/issues/38#issuecomment-1310803259
"ghcr.io/devcontainers/features/dotnet:1": {
"version": "7"
},
// Adds SSH support to the container
// Allowing the Github CLI `gh codespace ssh` to work
"ghcr.io/devcontainers/features/sshd:1": {
"version": "latest"
},
// Adds SQLite feature from apt install
// Also adds the SQLite VSCode extension
"ghcr.io/warrenbuckley/codespace-features/sqlite:1": {}
},
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-dotnettools.csharp"
],
// This is used in the prebuilds - so dotnet build (nuget restore and node stuff) is done
"updateContentCommand": "dotnet build umbraco.sln && dotnet dev-certs https --trust",
// Use 'forwardPorts' to make a list of ports inside the container available locallAdd "forwardPorts": [9000, 5000, 25],
// Port needed to help discover SMTP4Dev
"forwardPorts": [
5000
],
"portsAttributes": {
"5000": {
"label": "SMTP4Dev",
"protocol": "http",
"onAutoForward": "notify"
},
"9000": {
"label": "Umbraco HTTP",
"protocol": "http",
"onAutoForward": "notify"
},
"44331": {
"label": "Umbraco HTTPS",
"protocol": "https",
"onAutoForward": "notify"
}
},
"customizations": {
"codespaces": {
"openFiles": [
".github/codespaces-readme.md"
]
}
}
// [Optional] To reuse of your local HTTPS dev cert:
//
// 1. Export it locally using this command:
// * Windows PowerShell:
// dotnet dev-certs https --trust; dotnet dev-certs https -ep "$env:USERPROFILE/.aspnet/https/aspnetapp.pfx" -p "SecurePwdGoesHere"
// * macOS/Linux terminal:
// dotnet dev-certs https --trust; dotnet dev-certs https -ep "${HOME}/.aspnet/https/aspnetapp.pfx" -p "SecurePwdGoesHere"
//
// 2. Uncomment these 'remoteEnv' lines:
// "remoteEnv": {
// "ASPNETCORE_Kestrel__Certificates__Default__Password": "SecurePwdGoesHere",
// "ASPNETCORE_Kestrel__Certificates__Default__Path": "/home/vscode/.aspnet/https/aspnetapp.pfx",
// },
//
// 3. Next, copy your certificate into the container:
// 1. Start the container
// 2. Drag ~/.aspnet/https/aspnetapp.pfx into the root of the file explorer
// 3. Open a terminal in VS Code and run "mkdir -p /home/vscode/.aspnet/https && mv aspnetapp.pfx /home/vscode/.aspnet/https"
}
-98
View File
@@ -1,98 +0,0 @@
version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
# [Choice] .NET version: 6.0, 3.1, 6.0-bullseye, 3.1-bullseye, 6.0-focal, 3.1-focal
VARIANT: 6.0-bullseye
# Options
NODE_VERSION: "lts/*"
volumes:
- ..:/workspace:cached
# Overrides default command so things don't shut down after the process ends.
command: sleep infinity
# Uncomment the next line to use a non-root user for all processes.
# user: vscode
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
# (Adding the "ports" property to this file will not forward from a Codespace.)
# DotNetCore ENV Variables
# https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-5.0#environment-variables
environment:
- ConnectionStrings__umbracoDbDSN=Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True
- ConnectionStrings__umbracoDbDSN_ProviderName=Microsoft.Data.Sqlite
- Umbraco__CMS__Unattended__InstallUnattended=true
- Umbraco__CMS__Unattended__UnattendedUserName=Admin
- Umbraco__CMS__Unattended__UnattendedUserEmail=test@umbraco.com
- Umbraco__CMS__Unattended__UnattendedUserPassword=password1234
- Umbraco__CMS__Global__Smtp__Host=smtp4dev
- Umbraco__CMS__Global__Smtp__Port=25
- Umbraco__CMS__Global__Smtp__From=noreply@umbraco.test
smtp4dev:
image: rnwood/smtp4dev:v3
restart: always
ports:
# Change the number before : to the port the web interface should be accessible on
- '5000:80'
# Change the number before : to the port the SMTP server should be accessible on
- '25:25'
# Change the number before : to the port the IMAP server should be accessible on
# - '143:143'
volumes:
# This is where smtp4dev stores the database..
- smtp4dev-data:/smtp4dev
environment:
# Uncomment to customise these settings
#Specifies the virtual path from web server root where SMTP4DEV web interface will be hosted. e.g. "/" or "/smtp4dev"
#- ServerOptions__BasePath=/smtp4dev
#Specifies the server hostname. Used in auto-generated TLS certificate if enabled.
- ServerOptions__HostName=smtp4dev
#Specifies the path where the database will be stored relative to APPDATA env var on Windows or XDG_CONFIG_HOME on non-Windows. Specify "" to use an in memory database.
#- ServerOptions__Database=database.db
#Specifies the number of messages to keep
#- ServerOptions__NumberOfMessagesToKeep=100
#Specifies the number of sessions to keep
#- ServerOptions__NumberOfSessionsToKeep=100
#Specifies the TLS mode to use. None=Off. StartTls=On demand if client supports STARTTLS. ImplicitTls=TLS as soon as connection is established.
#- ServerOptions__TlsMode=None
#Specifies the TLS certificate to use if TLS is enabled/requested. Specify "" to use an auto-generated self-signed certificate (then see console output on first startup)
#- ServerOptions__TlsCertificate=
#Sets the name of the SMTP server that will be used to relay messages or "" if messages should not be relayed
#- RelayOptions__SmtpServer=
#Sets the port number for the SMTP server used to relay messages.
#- RelayOptions__SmtpPort=25
#Specifies a comma separated list of recipient addresses for which messages will be relayed. An empty list means that no messages are relayed.
#- RelayOptions__AllowedEmailsString=
#Specifies the address used in MAIL FROM when relaying messages. (Sender address in message headers is left unmodified). The sender of each message is used if not specified.
#- RelayOptions__SenderAddress=
#The username for the SMTP server used to relay messages. If "" no authentication is attempted.
#- RelayOptions__Login=
#The password for the SMTP server used to relay messages
#- RelayOptions__Password=
#Specifies the port the IMAP server will listen on - allows standard email clients to view/retrieve messages
#"ServerOptions__ImapPort": 143
volumes:
smtp4dev-data:
+43 -393
View File
@@ -1,393 +1,43 @@
# Version: 1.6.2 (Using https://semver.org/)
# Updated: 2020-11-02
# See https://github.com/RehanSaeed/EditorConfig/releases for release notes.
# See https://github.com/RehanSaeed/EditorConfig for updates to this file.
# See http://EditorConfig.org for more information about .editorconfig files.
##########################################
# Common Settings
##########################################
# This file is the top-most EditorConfig file
root = true
# All Files
[*]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
##########################################
# File Extension Settings
##########################################
# Visual Studio Solution Files
[*.sln]
indent_style = tab
# Visual Studio XML Project Files
[*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}]
indent_size = 2
# XML Configuration Files
[*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}]
indent_size = 2
# JSON Files
[*.{json,json5,webmanifest}]
indent_size = 2
# YAML Files
[*.{yml,yaml}]
indent_size = 2
# Markdown Files
[*.md]
trim_trailing_whitespace = false
# Web Files
[*.{htm,html,js,jsm,ts,tsx,css,sass,scss,less,svg,vue}]
indent_size = 2
# Batch Files
[*.{cmd,bat}]
end_of_line = crlf
# Bash Files
[*.sh]
end_of_line = lf
# Makefiles
[Makefile]
indent_style = tab
[*.js]
trim_trailing_whitespace = true
[*.less]
trim_trailing_whitespace = false
##########################################
# .NET Language Conventions
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions
##########################################
# .NET Code Style Settings
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#net-code-style-settings
[*.{cs,csx,cake,vb,vbx}]
# "this." and "Me." qualifiers
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#this-and-me
dotnet_style_qualification_for_field = false:suggestion
dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
# Language keywords instead of framework type names for type references
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#language-keywords
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
dotnet_style_predefined_type_for_member_access = true:warning
# Modifier preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#normalize-modifiers
dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:warning
dotnet_style_readonly_field = true:warning
# Parentheses preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parentheses-preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
# Expression-level preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
dotnet_style_object_initializer = true:warning
dotnet_style_collection_initializer = true:warning
dotnet_style_explicit_tuple_names = true:warning
dotnet_style_prefer_inferred_tuple_names = true:warning
dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
dotnet_style_prefer_auto_properties = true:warning
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
dotnet_style_prefer_conditional_expression_over_assignment = false:suggestion
dotnet_style_prefer_conditional_expression_over_return = false:suggestion
dotnet_style_prefer_compound_assignment = true:warning
# Null-checking preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#null-checking-preferences
dotnet_style_coalesce_expression = true:warning
dotnet_style_null_propagation = true:warning
# Parameter preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parameter-preferences
dotnet_code_quality_unused_parameters = all:warning
# More style options (Undocumented)
# https://github.com/MicrosoftDocs/visualstudio-docs/issues/3641
dotnet_style_operator_placement_when_wrapping = end_of_line
# https://github.com/dotnet/roslyn/pull/40070
dotnet_style_prefer_simplified_interpolation = true:warning
# File header preferences
file_header_template = Copyright (c) Umbraco.\nSee LICENSE for more details.
dotnet_diagnostic.SA1633.severity = none # Suppressed until we decide to enforce it
dotnet_diagnostic.SA1636.severity = none # Suppressed since we are using StyleCop
# C# Code Style Settings
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-code-style-settings
[*.{cs,csx,cake}]
# Implicit and explicit types
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#implicit-and-explicit-types
csharp_style_var_for_built_in_types = never
csharp_style_var_when_type_is_apparent = true:warning
csharp_style_var_elsewhere = false:warning
# Expression-bodied members
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-bodied-members
csharp_style_expression_bodied_methods = true:suggestion
csharp_style_expression_bodied_constructors = true:suggestion
csharp_style_expression_bodied_operators = true:suggestion
csharp_style_expression_bodied_properties = true:suggestion
csharp_style_expression_bodied_indexers = true:suggestion
csharp_style_expression_bodied_accessors = true:suggestion
csharp_style_expression_bodied_lambdas = true:suggestion
csharp_style_expression_bodied_local_functions = true:suggestion
# Pattern matching
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#pattern-matching
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
csharp_style_pattern_matching_over_as_with_null_check = true:warning
# Inlined variable declarations
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#inlined-variable-declarations
csharp_style_inlined_variable_declaration = true:warning
# Expression-level preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences
csharp_prefer_simple_default_expression = true:warning
# "Null" checking preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-null-checking-preferences
csharp_style_throw_expression = true:warning
csharp_style_conditional_delegate_call = true:warning
# Code block preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#code-block-preferences
csharp_prefer_braces = true:warning
# Unused value preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#unused-value-preferences
csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
# Index and range preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#index-and-range-preferences
csharp_style_prefer_index_operator = true:warning
csharp_style_prefer_range_operator = true:warning
# Miscellaneous preferences
# https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#miscellaneous-preferences
csharp_style_deconstructed_variable_declaration = true:warning
csharp_style_pattern_local_over_anonymous_function = true:warning
csharp_using_directive_placement = outside_namespace:warning
csharp_prefer_static_local_function = true:warning
csharp_prefer_simple_using_statement = true:suggestion
##########################################
# .NET Formatting Conventions
# https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference#formatting-conventions
##########################################
# Organize usings
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#organize-using-directives
dotnet_sort_system_directives_first = true
# Newline options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#new-line-options
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#indentation-options
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = no_change
csharp_indent_block_contents = true
csharp_indent_braces = false
csharp_indent_case_contents_when_block = false
# Spacing options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#spacing-options
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_after_comma = true
csharp_space_before_comma = false
csharp_space_after_dot = false
csharp_space_before_dot = false
csharp_space_after_semicolon_in_for_statement = true
csharp_space_before_semicolon_in_for_statement = false
csharp_space_around_declaration_statements = false
csharp_space_before_open_square_brackets = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_square_brackets = false
# Wrapping options
# https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#wrap-options
csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true
##########################################
# .NET Naming Conventions
# https://docs.microsoft.com/visualstudio/ide/editorconfig-naming-conventions
##########################################
[*.{cs,csx,cake,vb,vbx}]
dotnet_diagnostic.CS1591.severity = suggestion
##########################################
# Styles
##########################################
# camel_case_style - Define the camelCase style
dotnet_naming_style.camel_case_style.capitalization = camel_case
# pascal_case_style - Define the PascalCase style
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# first_upper_style - The first character must start with an upper-case character
dotnet_naming_style.first_upper_style.capitalization = first_word_upper
# prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I'
dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case
dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I
# prefix_type_parameters_with_t_style - Generic Type Parameters must be PascalCase and the first character must be a 'T'
dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case
dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T
# disallowed_style - Anything that has this style applied is marked as disallowed
dotnet_naming_style.disallowed_style.capitalization = pascal_case
dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____
dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____
# internal_error_style - This style should never occur... if it does, it indicates a bug in file or in the parser using the file
dotnet_naming_style.internal_error_style.capitalization = pascal_case
dotnet_naming_style.internal_error_style.required_prefix = ____INTERNAL_ERROR____
dotnet_naming_style.internal_error_style.required_suffix = ____INTERNAL_ERROR____
##########################################
# .NET Design Guideline Field Naming Rules
# Naming rules for fields follow the .NET Framework design guidelines
# https://docs.microsoft.com/dotnet/standard/design-guidelines/index
##########################################
# All public/protected/protected_internal constant fields must be PascalCase
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal, internal, private
dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const
dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = pascal_case_style
dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning
# All public/protected/protected_internal static readonly fields must be PascalCase
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected, protected_internal
dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly
dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style
dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning
# No other public/protected/protected_internal fields are allowed
# https://docs.microsoft.com/dotnet/standard/design-guidelines/field
dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected, protected_internal
dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style
dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error
# This rule should never fire. However, it's included for at least two purposes:
# First, it helps to understand, reason about, and root-case certain types of issues, such as bugs in .editorconfig parsers.
# Second, it helps to raise immediate awareness if a new field type is added (as occurred recently in C#).
dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_accessibilities = *
dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_kinds = field
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_check_uncovered_field_case_group
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style
dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error
##########################################
# Other Naming Rules
##########################################
# All of the following must be PascalCase:
# - Namespaces
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-namespaces
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
# - Classes and Enumerations
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md
# - Delegates
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces#names-of-common-types
# - Constructors, Properties, Events, Methods
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-type-members
dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property
dotnet_naming_rule.element_rule.symbols = element_group
dotnet_naming_rule.element_rule.style = pascal_case_style
dotnet_naming_rule.element_rule.severity = warning
# Interfaces use PascalCase and are prefixed with uppercase 'I'
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
dotnet_naming_symbols.interface_group.applicable_kinds = interface
dotnet_naming_rule.interface_rule.symbols = interface_group
dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style
dotnet_naming_rule.interface_rule.severity = warning
# Generics Type Parameters use PascalCase and are prefixed with uppercase 'T'
# https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces
dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter
dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group
dotnet_naming_rule.type_parameter_rule.style = prefix_type_parameters_with_t_style
dotnet_naming_rule.type_parameter_rule.severity = warning
# Function parameters use camelCase
# https://docs.microsoft.com/dotnet/standard/design-guidelines/naming-parameters
dotnet_naming_symbols.parameters_group.applicable_kinds = parameter
dotnet_naming_rule.parameters_rule.symbols = parameters_group
dotnet_naming_rule.parameters_rule.style = camel_case_style
dotnet_naming_rule.parameters_rule.severity = warning
# Instance fields use camelCase and are prefixed with '_'
dotnet_naming_rule.instance_fields_should_be_camel_case.severity = warning
dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
dotnet_naming_symbols.instance_fields.applicable_kinds = field
dotnet_naming_style.instance_field_style.capitalization = camel_case
dotnet_naming_style.instance_field_style.required_prefix = _
##########################################
# License
##########################################
# The following applies as to the .editorconfig file ONLY, and is
# included below for reference, per the requirements of the license
# corresponding to this .editorconfig file.
# See: https://github.com/RehanSaeed/EditorConfig
#
# MIT License
#
# Copyright (c) 2017-2019 Muhammad Rehan Saeed
# Copyright (c) 2019 Henry Gabryjelski
#
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject
# to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
##########################################
# editorconfig.org
# top-most EditorConfig file
root = true
# Default settings:
# A newline ending every file
# Use 4 spaces as indentation
[*]
insert_final_newline = true
end_of_line = crlf
indent_style = space
indent_size = 4
# Trim trailing whitespace, limited support.
# https://github.com/editorconfig/editorconfig/wiki/Property-research:-Trim-trailing-spaces
trim_trailing_whitespace = true
[*.{cs,vb}]
dotnet_style_predefined_type_for_locals_parameters_members = true:error
dotnet_naming_rule.private_members_with_underscore.symbols = private_fields
dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
dotnet_naming_rule.private_members_with_underscore.severity = suggestion
dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_style.prefix_underscore.capitalization = camel_case
dotnet_naming_style.prefix_underscore.required_prefix = _
# https://github.com/MicrosoftDocs/visualstudio-docs/blob/master/docs/ide/editorconfig-code-style-settings-reference.md
[*.cs]
csharp_style_var_for_built_in_types = true:suggestion
csharp_style_var_when_type_is_apparent = true:suggestion
csharp_style_var_elsewhere = true:suggestion
csharp_prefer_braces = false : none
[*.js]
trim_trailing_whitespace = true
[*.less]
trim_trailing_whitespace = false
-5
View File
@@ -1,5 +0,0 @@
UMBRACO_CLIENT_ID=umbraco-back-office-mcp
UMBRACO_CLIENT_SECRET=1234567890
UMBRACO_BASE_URL=https://localhost:44339
NODE_TLS_REJECT_UNAUTHORIZED=0
UMBRACO_INCLUDE_TOOL_COLLECTIONS=data-type,document-type,document,media-type,media
-10
View File
@@ -1,4 +1,3 @@
* text=auto
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
@@ -44,9 +43,6 @@
*.hs text=auto
*.json text=auto
*.xml text=auto
*.resx text=auto
*.yml text eol=lf core.whitespace whitespace=tab-in-indent,trailing-space,tabwidth=2
*.sh eol=lf
*.csproj text=auto merge=union
*.vbproj text=auto merge=union
@@ -55,9 +51,3 @@
*.sln text=auto eol=crlf merge=union
*.gitattributes text=auto
# Generated files - hidden by default in GitHub diffs
src/Umbraco.Web.UI.Client/src/packages/core/backend-api/** linguist-generated
src/Umbraco.Web.UI.Login/src/api/** linguist-generated
templates/UmbracoExtension/Client/src/api/** linguist-generated
src/Umbraco.Cms.Api.Management/OpenApi.json linguist-generated
+166 -145
View File
@@ -1,195 +1,216 @@
# Umbraco CMS Build
This guide will explain how you can build the Umbraco CMS from the source code. You will most likely want to do this if your are setting up a local development environment for contributing code updates to the project. You will need this in order to develop and test your fix or feature.
## Are you sure?
In order to use Umbraco as a CMS and build your website with it, you should not build it yourself. If you're reading this then you're trying to contribute to Umbraco or you're debugging a complex issue.
- Are you about to [create a pull request for Umbraco][contribution guidelines]?
- Are you trying to get to the bottom of a problem in your existing Umbraco installation?
- Are you about to create a pull request for Umbraco?
- Are you trying to get to the bottom of a problem in your existing Umbraco installation?
If the answer is yes, please read on. Otherwise, make sure to head on over [to the releases page](https://releases.umbraco.com) and start using Umbraco CMS as intended.
If the answer is yes, please read on. Otherwise, make sure to head on over [to the download page](https://our.umbraco.com/download) and start using Umbraco CMS as intended.
## Table of contents
**Table of contents**
↖️ You can jump to any section by using the "table of contents" button ( ![Table of contents icon](img/tableofcontentsicon.svg) ) above.
[Building from source](#building-from-source)
* [The quick build](#quick)
* [Build infrastructure](#build-infrastructure)
* [Properties](#properties)
* [GetUmbracoVersion](#getumbracoversion)
* [SetUmbracoVersion](#setumbracoversion)
* [Build](#build)
* [Build-UmbracoDocs](#build-umbracodocs)
* [Verify-NuGet](#verify-nuget)
* [Cleaning up](#cleaning-up)
## Working with the Umbraco source code
[Azure DevOps](#azure-devops)
Did you read ["Are you sure"](#are-you-sure)?
[Quirks](#quirks)
* [Powershell quirks](#powershell-quirks)
* [Git quirks](#git-quirks)
[More details about contributing to Umbraco and how to use the GitHub tooling can be found in our guide to contributing.][contribution guidelines]
If you want to run a build without debugging, see [Building from source](#building-from-source) below. This runs the build in the same way it is run on our build servers.
If you've got this far and are keen to get stuck in helping us fix a bug or implement a feature, great! Please read on...
### Prerequisites
In order to work with the Umbraco source code locally, first make sure you have the following installed.
- Your favourite IDE: [Visual Studio 2022 v17+ with .NET 7+](https://visualstudio.microsoft.com/vs/), [Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/)
- [dotnet SDK v9+](https://dotnet.microsoft.com/en-us/download)
- [Node.js v20+](https://nodejs.org/en/download/)
- npm v10+ (installed with Node.js)
- [Git command line](https://git-scm.com/download/)
### Familiarizing yourself with the code
Umbraco is a .NET application using C#. The solution is broken down into multiple projects. There are several class libraries. The `Umbraco.Web.UI` project is the main project that hosts the back office and login screen. This is the project you will want to run to see your changes.
There are two web projects in the solution with client-side assets based on TypeScript, `Umbraco.Web.UI.Client` and `Umbraco.Web.UI.Login`.
There are a few different ways to work locally when implementing features or fixing issues with the Umbraco CMS. Depending on whether you are working solely on the front-end, solely on the back-end, or somewhere in between, you may find different workflows work best for you.
Here are some suggestions based on how we work on developing Umbraco at HQ.
### First checkout
When you first clone the source code, build the whole solution via your IDE. You can then start the `Umbraco.Web.UI` project via the IDE or the command line and should find everything across front and back-end is built and running.
```
cd <solution root>\src\Umbraco.Web.UI
dotnet run --no-build
```
When the page loads in your web browser, you can follow the installer to set up a database for debugging. When complete, you will have an empty Umbraco installation to begin working with. You may also wish to install a [starter kit][https://marketplace.umbraco.com/category/themes-&-starter-kits] to ease your debugging.
### Back-end only changes
If you are working on back-end only features, when switching branches or pulling down the latest from GitHub, you will find the front-end getting rebuilt periodically when you look to build the back-end changes. This can take a while and slow you down. So if for a period of time you don't care about changes in the front-end, you can disable this build step.
Go to `Umbraco.Cms.StaticAssets.csproj` and comment out the following lines of MsBuild by adding a REM statement in front:
```
REM npm ci --no-fund --no-audit --prefer-offline
REM npm run build:for:cms
```
Just be careful not to include this change in your PR.
### Front-end only changes
Conversely, if you are working on front-end only, you want to build the back-end once and then run it. Before you do so, update the configuration in `appSettings.json` to add the following under `Umbraco:Cms:Security`:
```json
"BackOfficeHost": "http://localhost:5173",
"AuthorizeCallbackPathName": "/oauth_complete",
"AuthorizeCallbackLogoutPathName": "/logout",
"AuthorizeCallbackErrorPathName": "/error",
"BackOfficeTokenCookie": {
"SameSite": "None"
}
```
> [!NOTE]
> If you get stuck in a login loop, try clearing your browser cookies for localhost, and make sure that the `Umbraco:Cms:Security:BackOfficeTokenCookie:SameSite` setting is set to `None`.
Then run Umbraco from the command line.
```
cd <solution root>\src\Umbraco.Web.UI
dotnet run --no-build
```
In another terminal window, run the following to watch the front-end changes and launch Umbraco using the URL indicated from this task.
```
cd <solution root>\src\Umbraco.Web.UI.Client
npm run dev:server
```
You'll find as you make changes to the front-end files, the updates will be picked up and your browser refreshed automatically.
> [!NOTE]
> The caching for the back office has been described as 'aggressive' so we often find it's best when making back office changes to [disable caching in the browser (check "Disable cache" on the "Network" tab of developer tools)][disable browser caching] to help you to see the changes you're making.
Whilst most of the backoffice code lives in `Umbraco.Web.UI.Client`, the login screen is in a separate project. If you do any work with that you can build with:
```
cd <solution root>\src\Umbraco.Web.UI.Login
npm run build
```
In both front-end projects, if you've refreshed your branch from the latest on GitHub you may need to update front-end dependencies.
To do that, run:
```
npm ci --no-fund --no-audit --prefer-offline
```
### Full-stack changes
If working across both front and back-end, follow both methods and use `dotnet watch`, or re-run `dotnet run` (or `dotnet build` followed by `dotnet run --no-build`) whenever you need to update the back-end code.
Request and response models used by the management APIs are made available client-side as generated code. If you make changes to the management API, you can re-generate the typed client code with:
```
cd <solution root>\src\Umbraco.Web.UI.Client
npm run generate:server-api-dev
```
Please also update the `OpenApi.json` file held in the solution by copying and pasting the output from `/umbraco/swagger/management/swagger.json`.
## Building from source
Did you read ["Are you sure"](#are-you-sure)?
Do note that this is only required if you want to test out your custom changes in a separate site (not the one in the Umbraco.Web.UI), if you just want to test your changes you can run the included test site using: `dotnet run` from `src/Umbraco.Web.UI/`
### Quick!
You may want to build a set of NuGet packages with your changes, this can be done using the dotnet pack command.
To build Umbraco, fire up PowerShell and move to Umbraco's repository root (the directory that contains `src`, `build`, `LICENSE.md`...). There, trigger the build with the following command:
First enter the root of the project in a command line environment, and then use the following command to build the NuGet packages:
build/build.ps1
If you only see a build.bat-file, you're probably on the wrong branch. If you switch to the correct branch (v8/contrib) the file will appear and you can build it.
`dotnet pack -c Release -o Build.Out`
You might run into [Powershell quirks](#powershell-quirks).
This will restore and build the project using the release configuration, and put all the outputted files in a folder called `Build.Out`
If it runs without errors; Hooray! Now you can continue with [the next step](CONTRIBUTING.md#how-do-i-begin) and open the solution and build it.
You can then add these as a local NuGet feed using the following command:
### Build Infrastructure
`dotnet nuget add source <Path to Build.Out folder> -n MyLocalFeed`
The Umbraco Build infrastructure relies on a PowerShell object. The object can be retrieved with:
This will add a local nuget feed with the name "MyLocalFeed" and you'll now be able to use your custom built NuGet packages.
$ubuild = build/build.ps1 -get
The object exposes various properties and methods that can be used to fine-grain build Umbraco. Some, but not all, of them are detailed below.
#### Properties
The object exposes the following properties:
* `SolutionRoot`: the absolute path to the solution root
* `VisualStudio`: a Visual Studio object (see below)
* `NuGet`: the absolute path to the NuGet executable
* `Zip`: the absolute path to the 7Zip executable
* `VsWhere`: the absolute path to the VsWhere executable
* `NodePath`: the absolute path to the Node install
* `NpmPath`: the absolute path to the Npm install
The Visual Studio object is `null` when Visual Studio has not been detected (eg on VSTS). When not null, the object exposes the following properties:
* `Path`: Visual Studio installation path (eg some place under `Program Files`)
* `Major`: Visual Studio major version (eg `15` for VS 2017)
* `Minor`: Visual Studio minor version
* `MsBuild`: the absolute path to the MsBuild executable
#### GetUmbracoVersion
Gets an object representing the current Umbraco version. Example:
$v = $ubuild.GetUmbracoVersion()
Write-Host $v.Semver
The object exposes the following properties:
* `Semver`: the semver object representing the version
* `Release`: the main part of the version (eg `7.6.33`)
* `Comment`: the pre release part of the version (eg `alpha02`)
* `Build`: the build number part of the version (eg `1234`)
#### SetUmbracoVersion
Modifies Umbraco files with the new version.
>This entirely replaces the legacy `UmbracoVersion.txt` file. Do *not* edit version infos in files.
The version must be a valid semver version. It can include a *pre release* part (eg `alpha02`) and/or a *build number* (eg `1234`). Examples:
$ubuild.SetUmbracoVersion("7.6.33")
$ubuild.SetUmbracoVersion("7.6.33-alpha.2")
$ubuild.SetUmbracoVersion("7.6.33+1234")
$ubuild.SetUmbracoVersion("7.6.33-beta.5+5678")
#### Build
Builds Umbraco. Temporary files are generated in `build.tmp` while the actual artifacts (zip files, NuGet packages...) are produced in `build.out`. Example:
$ubuild.Build()
Some log files, such as MsBuild logs, are produced in `build.tmp` too. The `build` directory should remain clean during a build.
**Note: web.config**
Building Umbraco requires a clean `web.config` file in the `Umbraco.Web.UI` project. If a `web.config` file already exists, the `pre-build` task (see below) will save it as `web.config.temp-build` and replace it with a clean copy of `web.Template.config`. The original file is replaced once it is safe to do so, by the `pre-packages` task.
#### Build-UmbracoDocs
Builds umbraco documentation. Temporary files are generated in `build.tmp` while the actual artifacts (docs...) are produced in `build.out`. Example:
Build-UmbracoDocs
Some log files, such as MsBuild logs, are produced in `build.tmp` too. The `build` directory should remain clean during a build.
#### Verify-NuGet
Verifies that projects all require the same version of their dependencies, and that NuSpec files require versions that are consistent with projects. Example:
Verify-NuGet
### Cleaning up
Once the solution has been used to run a site, one may want to "reset" the solution in order to run a fresh new site again.
The easiest way to do this by deleting the following files and folders:
At the very minimum, you want
- src/Umbraco.Web.UI/appsettings.json
- src/Umbraco.Web.UI/umbraco/Data
git clean -Xdf src/Umbraco.Web.UI/App_Data
rm src/Umbraco.Web.UI/web.config
You only have to remove the connection strings from the appsettings, but removing the data folder ensures that the sqlite database gets deleted too.
Then, a simple 'Rebuild All' in Visual Studio will recreate a fresh `web.config` but should be quite fast (since it does not really need to rebuild anything).
Next time you run a build the `appsettings.json` file will be re-created in its default state.
The `clean` Git command force (`-f`) removes (`-X`, note the capital X) all files and directories (`-d`) that are ignored by Git.
This will leave media files and views around, but in most cases, it will be enough.
To perform a more complete clear, you will want to also delete the content of the media, views, scripts... directories.
The following command will force remove all untracked files and directories, whether they are ignored by Git or not. Combined with `git reset` it can recreate a pristine working directory.
The following command will force remove all untracked files and directories, whether they are ignored by Git or not. Combined with `git reset` it can recreate a pristine working directory.
git clean -xdf .
For git documentation see:
- git [clean](https://git-scm.com/docs/git-clean)
- git [reset](https://git-scm.com/docs/git-reset)
* git [clean](<https://git-scm.com/docs/git-clean>)
* git [reset](<https://git-scm.com/docs/git-reset>)
## Azure DevOps
Umbraco uses Azure DevOps for continuous integration, nightly builds and release builds. The Umbraco CMS project on DevOps [is available for anonymous users](https://umbraco.visualstudio.com/Umbraco%20Cms)..
Umbraco uses Azure DevOps for continuous integration, nightly builds and release builds. The Umbraco CMS project on DevOps [is available for anonymous users](https://umbraco.visualstudio.com/Umbraco%20Cms).
The produced artifacts are published in a container that can be downloaded from DevOps called "nupkg" which contains all the NuGet packages that got built.
DevOps uses the `Build-Umbraco` command several times, each time passing a different *target* parameter. The supported targets are:
* `pre-build`: prepares the build
* `compile-belle`: compiles Belle
* `compile-umbraco`: compiles Umbraco
* `pre-tests`: prepares the tests
* `compile-tests`: compiles the tests
* `pre-packages`: prepares the packages
* `pkg-zip`: creates the zip files
* `pre-nuget`: prepares NuGet packages
* `pkg-nuget`: creates NuGet packages
All these targets are executed when `Build-Umbraco` is invoked without a parameter (or with the `all` parameter). On VSTS, compilations (of Umbraco and tests) are performed by dedicated DevOps tasks. Similarly, creating the NuGet packages is also performed by dedicated DevOps tasks.
Finally, the produced artifacts are published in two containers that can be downloaded from DevOps: `zips` contains the zip files while `nuget` contains the NuGet packages.
>During a DevOps build, some environment `UMBRACO_*` variables are exported by the `pre-build` target and can be reused in other targets *and* in DevOps tasks. The `UMBRACO_TMP` environment variable is used in `Umbraco.Tests` to disable some tests that have issues with DevOps at the moment.
## Quirks
### PowerShell Quirks
There is a good chance that running `build.ps1` ends up in error, with messages such as
>The file ...\build.ps1 is not digitally signed. You cannot run this script on the current system. For more information about running scripts and setting execution policy, see about_Execution_Policies.
PowerShell has *Execution Policies* that may prevent the script from running. You can check the current policies with:
PS> Get-ExecutionPolicy -List
Scope ExecutionPolicy
----- ---------------
MachinePolicy Undefined
UserPolicy Undefined
Process Undefined
CurrentUser Undefined
LocalMachine RemoteSigned
Policies can be `Restricted`, `AllSigned`, `RemoteSigned`, `Unrestricted` and `Bypass`. Scopes can be `MachinePolicy`, `UserPolicy`, `Process`, `CurrentUser`, `LocalMachine`. You need the current policy to be `RemoteSigned`&mdash;as long as it is `Undefined`, the script cannot run. You can change the current user policy with:
PS> Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
Alternatively, you can do it at machine level, from within an elevated PowerShell session:
PS> Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy RemoteSigned
And *then* the script should run. It *might* however still complain about executing scripts, with messages such as:
>Security warning - Run only scripts that you trust. While scripts from the internet can be useful, this script can potentially harm your computer. If you trust this script, use the Unblock-File cmdlet to allow the script to run without this warning message. Do you want to run ...\build.ps1?
[D] Do not run [R] Run once [S] Suspend [?] Help (default is "D"):
This is usually caused by the scripts being *blocked*. And that usually happens when the source code has been downloaded as a Zip file. When Windows downloads Zip files, they are marked as *blocked* (technically, they have a Zone.Identifier alternate data stream, with a value of "3" to indicate that they were downloaded from the Internet). And when such a Zip file is un-zipped, each and every single file is also marked as blocked.
The best solution is to unblock the Zip file before un-zipping: right-click the files, open *Properties*, and there should be a *Unblock* checkbox at the bottom of the dialog. If, however, the Zip file has already been un-zipped, it is possible to recursively unblock all files from PowerShell with:
PS> Get-ChildItem -Recurse *.* | Unblock-File
### Git Quirks
Git might have issues dealing with long file paths during build. You may want/need to enable `core.longpaths` support (see [this page](https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path) for details).
[ contribution guidelines]: CONTRIBUTING.md "Read the guide to contributing for more details on contributing to Umbraco"
[ disable browser caching ]: https://techwiser.com/disable-cache-google-chrome-firefox "Instructions on how to disable browser caching in Chrome and Firefox"
+92
View File
@@ -0,0 +1,92 @@
# Umbraco Code of Conduct
## Preamble
We are the friendly CMS. And our friendliness stems from our values. That's why we have set for ourselves, Umbraco HQ, and the community, five values to guide us in everything we do:
* Trust - We believe in and empower people
* Respect - We treat others as we would like to be treated
* Open - We share our thoughts and knowledge
* Hungry - We want to do things better, best is next
* Friendly - We want to build long-lasting relationships
With these values in mind, we want to offer the Umbraco community a code of conduct that specifies a baseline standard of behavior so that people with different social values and communication styles can work together.
This code of conduct is based on the widely used Contributor Covenant, as described in [https://www.contributor-covenant.org/](https://www.contributor-covenant.org/)
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Enforcement Responsibilities
Community leaders (e.g. Meetup & festival organizers, moderators, maintainers, ...) are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
Specific enforcement steps are listed in the [Code of Conduct Enforcement Guidelines](https://github.com/umbraco/Umbraco-CMS/blob/v8/contrib/.github/CODE_OF_CONDUCT_ENFORCEMENT.md) document which is an appendix of this document, updated and maintained by the Code of Conduct Team.
## Scope
This Code of Conduct applies within all community spaces and events supported by Umbraco HQ or using the Umbraco name. It also applies when an individual is officially representing the community in public spaces.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior, may be reported at [conduct@umbraco.com](mailto:conduct@umbraco.com). All complaints will be reviewed and investigated promptly and fairly.
Or alternatively, you can reach out directly to any of the team members behind the address above:
* Sebastiaan Janssen (He, Him - Languages spoken: English, Dutch, Danish(Read)) [sebastiaan@umbraco.com](mailto:sebastiaan@umbraco.com)
* Ilham Boulghallat (She, Her - Languages spoken: English, French, Arabic) [ilham@umbraco.com](mailto:ilham@umbraco.com)
* Arnold Visser (He, Him - Languages spoken: English, Dutch) [arnold@umbraco.com](mailto:arnold@umbraco.com)
The review process is done with full respect for the privacy and security of the reporter of any incident.
People with a conflict of interest should exclude themselves or if necessary be excluded by the other team members.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
**1. Correction**
Community Impact: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
Consequence: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
**2. Warning**
Community Impact: A violation through a single incident or series of actions.
Consequence: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
**3. Temporary Ban**
Community Impact: A serious violation of community standards, including sustained inappropriate behavior.
Consequence: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
**4. Permanent Ban**
Community Impact: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
Consequence: A permanent ban from any sort of public interaction within the community.
## Attribution
This Code of Conduct is adapted from the Contributor Covenant, version 2.0, available at [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html).
This Code of Conduct will be maintained and reviewed by the team listed above.
+57
View File
@@ -0,0 +1,57 @@
# Umbraco Code of Conduct Enforcement guidelines - Consequence Ladder
These are the steps followed by the [Umbraco Code of Conduct Team](https://github.com/umbraco/Umbraco-CMS/blob/v8/contrib/.github/CODE_OF_CONDUCT.md) when we respond to an issue or incident brought to our attention by a community member.
This is an appendix to the Code of Conduct and is updated and maintained by the Code of Conduct Team.
To make sure that all reports will be reviewed and investigated promptly and fairly, as highlighted in the Umbraco Code of Conduct, we are following [Mozillas Consequence Ladder approach](https://github.com/mozilla/inclusion/blob/master/code-of-conduct-enforcement/consequence-ladder.md).
This approach helps the Team enforce the Code of Conduct in a structured manner and can be used as a way of communicating escalation. Each time the Team takes an action (warning, ban) the individual is made aware of future consequences. The Team can either follow the order of the levels in the ladder or decide to jump levels. When needed, the team can go directly to a permanent ban.
**Level 0: No Action**
Recommendations do not indicate a violation of the Code of Conduct.
**Level 1: Simple Warning Issued**
A private, written warning from the Code of Conduct Team, with clarity of violation, consequences of continued behavior.
**Level 2: Warning**
A private, written warning from the Code of Conduct Team, with clarity of violation, consequences of continued behavior. Additionally:
* Communication of next-level consequences if behaviors are repeated (according to this ladder).
**Level 3: Warning + Mandatory Cooling Off Period (Access Retained)**
A private warning from the Code of Conduct Team, with clarity of violation, consequences of continued behavior. Additionally:
* Request to avoid interaction on community messaging platforms (public forums, Our, commenting on issues).
* This includes avoiding any interactions in any Umbraco channels, spaces/offices, as well as external channels like social media (e.g. Twitter, Facebook, LinkedIn). For example, 'following/liking/retweeting' would be considered a violation of these terms, and consequence would escalate according to this ladder.
* Require they do not interact with others in the report, or those who they suspect are involved in the report.
* Suggestions for 'out of office' type of message on platforms, to reduce curiosity, or suspicion among those not involved.
**Level 4: Temporary Ban (Access Revoked)**
Private communication of ban from the Code of Conduct Team, with clarity of violation, consequences of continued behavior. Additionally:
* 3-6 months imposed break.
* All accounts deactivated, or blocked during this time (Our, HQ Slack if applicable).
* Require to avoid interaction on community messaging platforms (public forums, Our, commenting on issues).
* This includes avoiding any interactions in any Umbraco channels, spaces/offices, as well as external channels like social media (e.g. Twitter, Facebook, LinkedIn). For example, 'following/liking/retweeting' would be considered a violation of these terms, and consequence would escalate according to this ladder.
* All community leadership roles (e.g. Community Teams, Meetup/festival organizer, Commit right on Github..) suspended. (onboarding/reapplication required outside of this process)
* No attendance at Umbraco events during the ban period.
* Not allowed to enter Umbraco HQ offices during the ban period.
* Permission to use the MVP title, if applicable, is revoked during this ban period.
* The community leaders running events and other initiatives are informed of the ban.
**Level 5: Permanent Ban**
Private communication of ban from the Code of Conduct Team, with clarity of violation, consequences of continued behavior. Additionally:
* All accounts deactivated permanently.
* No attendance at Umbraco events going forward.
* Not allowed to enter Umbraco HQ offices permanently.
* All community leadership roles (e.g. Community Teams, Meetup/festival organizer, Commit right on Github..) permanently suspended.
* Permission to use the MVP title, if applicable, revoked.
* The community leaders running events and other initiatives are informed of the ban.
Sources:
* [Mozilla Code of Conduct - Enforcement Consequence Ladder](https://github.com/mozilla/inclusion/blob/master/code-of-conduct-enforcement/consequence-ladder.md)
* [Drupal Conflict Resolution Policy and Process](https://www.drupal.org/conflict-resolution)
* [Django Code of Conduct - Enforcement Manual](https://www.djangoproject.com/conduct/enforcement-manual/)
+211 -68
View File
@@ -1,68 +1,211 @@
# Contributing to Umbraco CMS
👍🎉 First of all, thanks for taking the time to contribute! 🎉👍
These contribution guidelines are mostly just that - guidelines, not rules. This is what we've found to work best over the years, but if you choose to ignore them, we still love you! 💖 Use your best judgment, and feel free to propose changes to this document in a pull request.
We have a guide on [what to consider before you start](contributing-before-you-start.md) and more detailed guides at the end of this article.
## Contribution guide
This guide describes each step to make your first contribution:
1. **Fork**
Create a fork of [`Umbraco-CMS` on GitHub](https://github.com/umbraco/Umbraco-CMS)
![Fork the repository](img/forkrepositorynew.png)
2. **Clone**
When GitHub has created your fork, you can clone it in your favorite Git tool or on the command line with `git clone https://github.com/[YourUsername]/Umbraco-CMS`.
![Clone the fork](img/cloneforknew.png)
3. **Switch to the correct branch**
Switch to the `main` branch
4. **Branch out**
Create a new branch based on `main` and name it after the issue you're fixing. For example: `v15/bugfix/18132-rte-tinymce-onchange-value-check`.
Please follow this format for branches: `v{major}/{feature|bugfix|task|qa|improvement}/{issue}-{description}`.
This is a development branch for the particular issue you're working on, in this case, a bug-fix for issue number `18132` that affects Umbraco v.15.
Don't commit to `main`, create a new branch first.
5. **Build or run a Development Server**
You can build or run a Development Server with any IDE that supports .NET or the command line.
Read [Build or run a Development Server](BUILD.md) for the right approach to your needs.
6. **Change**
Make your changes, experiment, have fun, explore and learn, and don't be afraid. We welcome all contributions and will [happily give feedback](contributing-first-issue.md#questions).
7. **Commit and push**
Done? Yay! 🎉
Remember to commit to your branch. When it's ready, push the changes to your fork on GitHub.
8. **Create pull request**
On GitHub, in your forked repository (`https://github.com/[YourUsername]/Umbraco-CMS`), you will see a banner saying that you pushed a new branch and a button to make a pull request. Tap the button and follow the instructions.
Would you like to read further? [Creating a pull request and what happens next](contributing-creating-a-pr.md).
## Further contribution guides
- [Before you start](contributing-before-you-start.md)
- [Finding your first issue](contributing-first-issue.md)
- [Contributing to the new backoffice](https://docs.umbraco.com/umbraco-backoffice/)
- [Unwanted changes](contributing-unwanted-changes.md)
- [Other ways to contribute](contributing-other-ways-to-contribute.md)
# Contributing to Umbraco CMS
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
The following is a set of guidelines, for contributing to Umbraco CMS.
These are mostly guidelines, not rules. Use your best judgement, and feel free to propose changes to this document in a pull request.
Remember, we're a friendly bunch and are happy with whatever contribution you might provide. Below are guidelines for success that we've gathered over the years. If you choose to ignore them then we still love you 💖.
**Code of conduct**
This project and everyone participating in it, is governed by the [our Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [Sebastiaan Janssen - sj@umbraco.dk](mailto:sj@umbraco.dk).
**Table of contents**
[Contributing code changes](#contributing-code-changes)
* [Guidelines for contributions we welcome](#guidelines-for-contributions-we-welcome)
* [Ownership and copyright](#ownership-and-copyright)
* [What can I start with?](#what-can-i-start-with)
* [How do I begin?](#how-do-i-begin)
* [Pull requests](#pull-requests)
[Reviews](#reviews)
* [Styleguides](#styleguides)
* [The Core Contributors](#the-core-contributors-team)
* [Questions?](#questions)
[Working with the code](#working-with-the-code)
* [Building Umbraco from source code](#building-umbraco-from-source-code)
* [Working with the source code](#working-with-the-source-code)
* [Making changes after the PR is open](#making-changes-after-the-pr-is-open)
* [Which branch should I target for my contributions?](#which-branch-should-i-target-for-my-contributions)
* [Keeping your Umbraco fork in sync with the main repository](#keeping-your-umbraco-fork-in-sync-with-the-main-repository)
## Contributing code changes
This document gives you a quick overview on how to get started.
### Guidelines for contributions we welcome
Not all changes are wanted, so on occasion we might close a PR without merging it. We will give you feedback why we can't accept your changes and we'll be nice about it, thanking you for spending your valuable time.
We have [documented what we consider small and large changes](CONTRIBUTION_GUIDELINES.md). Make sure to talk to us before making large changes, so we can ensure that you don't put all your hard work into something we would not be able to merge.
Remember, it is always worth working on an issue from the `Up for grabs` list or even asking for some feedback before you send us a PR. This way, your PR will not be closed as unwanted.
#### Ownership and copyright
It is your responsibility to make sure that you're allowed to share the code you're providing us.
For example, you should have permission from your employer or customer to share code.
Similarly, if your contribution is copied or adapted from somewhere else, make sure that the license allows you to reuse that for a contribution to Umbraco-CMS.
If you're not sure, leave a note on your contribution and we will be happy to guide you.
When your contribution has been accepted, it will be [MIT licensed](https://github.com/umbraco/Umbraco-CMS/blob/v8/contrib/LICENSE.md) from that time onwards.
### What can I start with?
Unsure where to begin contributing to Umbraco? You can start by looking through [these `Up for grabs` issues](https://github.com/umbraco/Umbraco-CMS/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Acommunity%2Fup-for-grabs+)
### How do I begin?
Great question! The short version goes like this:
* **Fork** - create a fork of [`Umbraco-CMS` on GitHub](https://github.com/umbraco/Umbraco-CMS)
![Fork the repository](img/forkrepository.png)
* **Clone** - when GitHub has created your fork, you can clone it in your favorite Git tool
![Clone the fork](img/clonefork.png)
* **Switch to the correct branch** - switch to the `v8/contrib` branch
* **Build** - build your fork of Umbraco locally as described in [building Umbraco from source code](BUILD.md)
* **Change** - make your changes, experiment, have fun, explore and learn, and don't be afraid. We welcome all contributions and will [happily give feedback](#questions)
* **Commit** - done? Yay! 🎉 **Important:** create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-12345`. This means it's a temporary branch for the particular issue you're working on, in this case `12345`. When you have a branch, commit your changes. Don't commit to `v8/contrib`, create a new branch first.
* **Push** - great, now you can push the changes up to your fork on GitHub
* **Create pull request** - exciting! You're ready to show us your changes (or not quite ready, you just need some feedback to progress - you can now make use of GitHub's draft pull request status, detailed [here](https://github.blog/2019-02-14-introducing-draft-pull-requests/)). GitHub has picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go.
![Create a pull request](img/createpullrequest.png)
### Pull requests
The most successful pull requests usually look a like this:
* Fill in the required template (shown when starting a PR on GitHub), and link your pull request to an issue on the [issue tracker,](https://github.com/umbraco/Umbraco-CMS/issues) if applicable.
* Include screenshots and animated GIFs in your pull request whenever possible.
* Unit tests, while optional, are awesome. Thank you!
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.com/documentation/Reference/) is generated.
Again, these are guidelines, not strict requirements. However, the more information that you give to us, the more we have to work with when considering your contributions. Good documentation of a pull request can really speed up the time it takes to review and merge your work!
## Reviews
You've sent us your first contribution - congratulations! Now what?
The [pull request team](#the-pr-team) can now start reviewing your proposed changes and give you feedback on them. If it's not perfect, we'll either fix up what we need or we can request that you make some additional changes.
We have [a process in place which you can read all about](REVIEW_PROCESS.md). The very abbreviated version is:
- Your PR will get a reply within 48 hours
- An in-depth reply will be added within at most 2 weeks
- The PR will be either merged or rejected within at most 4 weeks
- Sometimes it is difficult to meet these timelines and we'll talk to you if this is the case.
### Styleguides
To be honest, we don't like rules very much. We trust you have the best of intentions and we encourage you to create working code. If it doesn't look perfect then we'll happily help clean it up.
That said, the Umbraco development team likes to follow the hints that ReSharper gives us (no problem if you don't have this installed) and we've added a `.editorconfig` file so that Visual Studio knows what to do with whitespace, line endings, etc.
### The Core Contributors team
The Core Contributors team consists of one member of Umbraco HQ, [Sebastiaan](https://github.com/nul800sebastiaan), who gets assistance from the following community members who have comitted to volunteering their free time:
- [Nathan Woulfe](https://github.com/nathanwoulfe)
- [Joe Glombek](https://github.com/glombek)
- [Laura Weatherhead](https://github.com/lssweatherhead)
- [Michael Latouche](https://github.com/mikecp)
- [Owain Williams](https://github.com/OwainWilliams)
These wonderful people aim to provide you with a first reply to your PR, review and test out your changes and on occasions, they might ask more questions. If they are happy with your work, they'll let Umbraco HQ know by approving the PR. Hq will have final sign-off and will check the work again before it is merged.
### Questions?
You can get in touch with [the core contributors team](#the-core-contributors-team) in multiple ways; we love open conversations and we are a friendly bunch. No question you have is stupid. Any question you have usually helps out multiple people with the same question. Ask away:
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward.
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.com/forum/contributing-to-umbraco-cms/) forum. The team monitors that one closely, so one of us will be on hand and ready to point you in the right direction.
## Working with the code
### Building Umbraco from source code
In order to build the Umbraco source code locally, first make sure you have the following installed.
* [Visual Studio 2019 v16.8+ (with .NET Core 3.0)](https://visualstudio.microsoft.com/vs/)
* [Node.js v10+](https://nodejs.org/en/download/)
* npm v6.4.1+ (installed with Node.js)
* [Git command line](https://git-scm.com/download/)
The easiest way to get started is to open `src\umbraco.sln` in Visual Studio 2019 (version 16.3 or higher, [the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
Alternatively, you can run `build.ps1` from the Powershell command line, which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `gulp dev` in `src\Umbraco.Web.UI.Client`. See [this page](BUILD.md) for more details.
![Gulp build in Visual Studio](img/gulpbuild.png)
After this build completes, you should be able to hit `F5` in Visual Studio to build and run the project. A IISExpress webserver will start and the Umbraco installer will pop up in your browser. Follow the directions there to get a working Umbraco install up and running.
### Working with the source code
Some parts of our source code are over 10 years old now. And when we say "old", we mean "mature" of course!
There are two big areas that you should know about:
1. The Umbraco backoffice is a extensible AngularJS app and requires you to run a `gulp dev` command while you're working with it, so changes are copied over to the appropriate directories and you can refresh your browser to view the results of your changes.
You may need to run the following commands to set up gulp properly:
```
npm cache clean --force
npm install
npm run build
```
The caching for the back office has been described as 'aggressive' so we often find it's best when making back office changes to disable caching in the browser to help you to see the changes you're making.
2. "The rest" is a C# based codebase, which is mostly ASP.NET MVC based. You can make changes, build them in Visual Studio, and hit `F5` to see the result.
To find the general areas for something you're looking to fix or improve, have a look at the following two parts of the API documentation.
* [The AngularJS based backoffice files](https://our.umbraco.com/apidocs/ui/#/api) (to be found in `src\Umbraco.Web.UI.Client\src`)
* [The C# application](https://our.umbraco.com/apidocs/csharp/)
### Which branch should I target for my contributions?
We like to use [Gitflow as much as possible](https://jeffkreeftmeijer.com/git-flow/), but don't worry if you are not familiar with it. The most important thing you need to know is that when you fork the Umbraco repository, the default branch is set to something, usually `v8/contrib`. If you are working on v8, this is the branch you should be targetting. For v7 contributions, please target 'v7/dev'.
Please note: we are no longer accepting features for v7 but will continue to merge bug fixes as and when they arise.
![Which branch should I target?](img/defaultbranch.png)
### Making changes after the PR is open
If you make the corrections we ask for in the same branch and push them to your fork again, the pull request automatically updates with the additional commit(s) so we can review it again. If all is well, we'll merge the code and your commits are forever part of Umbraco!
### Keeping your Umbraco fork in sync with the main repository
We recommend you to sync with our repository before you submit your pull request. That way, you can fix any potential merge conflicts and make our lives a little bit easier.
Also, if you have submitted a pull request three weeks ago and want to work on something new, you'll want to get the latest code to build against of course.
To sync your fork with this original one, you'll have to add the upstream url. You only have to do this once:
```
git remote add upstream https://github.com/umbraco/Umbraco-CMS.git
```
Then when you want to get the changes from the main repository:
```
git fetch upstream
git rebase upstream/v8/contrib
```
In this command we're syncing with the `v8/contrib` branch, but you can of course choose another one if needed.
(More info on how this works: [http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated](http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated))
### And finally
We welcome all kinds of contributions to this repository. If you don't feel you'd like to make code changes here, you can visit our [documentation repository](https://github.com/umbraco/UmbracoDocs) and use your experience to contribute to making the docs we have, even better. We also encourage community members to feel free to comment on others' pull requests and issues - the expertise we have is not limited to the Core Contributors and HQ. So, if you see something on the issue tracker or pull requests you feel you can add to, please don't be shy.
+35
View File
@@ -0,0 +1,35 @@
# Contributing to Umbraco CMS
When youre considering creating a pull request for Umbraco CMS, we will categorize them in two different sizes, small and large.
The process for both sizes is very similar, as [explained in the contribution document](CONTRIBUTING.md#how-do-i-begin).
## Small PRs
Bug fixes and small improvements - can be recognized by seeing a small number of changes and possibly a small number of new files.
Were usually able to handle small PRs pretty quickly. A community volunteer will do the initial review and flag it for Umbraco HQ as “community tested”. If everything looks good, it will be merged pretty quickly [as per the described process](REVIEW_PROCESS.md).
### Up for grabs
Umbraco HQ will regularly mark newly created issues on the issue tracker with the `Up for grabs` tag. This means that the proposed changes are wanted in Umbraco but the HQ does not have the time to make them at this time. We encourage anyone to pick them up and help out.
If you do start working on something, make sure to leave a small comment on the issue saying something like: "I'm working on this". That way other people stumbling upon the issue know they don't need to pick it up, someone already has.
## Large PRs
New features and large refactorings - can be recognized by seeing a large number of changes, plenty of new files, updates to package manager files (NuGets packages.config, NPMs packages.json, etc.).
We would love to follow the same process for larger PRs but this is not always possible due to time limitations and priorities that need to be aligned. We dont want to put up any barriers, but this document should set the correct expectations.
Please make sure to describe your idea in an issue, it helps to put in mockup screenshots or videos.
If the change makes sense for HQ to include in Umbraco CMS we will leave you some feedback on how wed like to see it being implemented.
If a larger pull request is encouraged by Umbraco HQ, the process will be similar to what is described in the [small PRs process](#small-prs) above, we strive to feedback within 14 days. Finalizing and merging the PR might take longer though as it will likely need to be picked up by the development team to make sure everything is in order. Well keep you posted on the progress.
It is highly recommended that you speak to the HQ before making large, complex changes.
### Pull request or package?
If it doesnt fit in CMS right now, we will likely encourage you to make it into a package instead. A package is a great way to check out popularity of a feature, learn how people use it, validate good usability and fix bugs.
Eventually, a package could "graduate" to be included in the CMS.
+2 -2
View File
@@ -6,8 +6,8 @@ body:
- type: input
id: "version"
attributes:
label: "Which Umbraco version are you using?"
description: "Please write the *exact* version, example: `10.1.0`. Click the Umbraco logo in the top left corner of the backoffice to find the version you're using."
label: "Which *exact* Umbraco version are you using? For example: 8.13.1 - don't just write v8"
description: "Use the help icon in the Umbraco backoffice to find the version you're using"
validations:
required: true
- type: textarea
+2 -2
View File
@@ -4,11 +4,11 @@ contact_links:
url: https://github.com/umbraco/Umbraco-CMS/discussions/new?category=features-and-ideas
about: Start a new discussion when you have ideas or feature requests, eventually discussions can turn into plans
- name: ⁉️ Support Question
url: https://forum.umbraco.com
url: https://our.umbraco.com
about: This issue tracker is NOT meant for support questions. If you have a question, please join us on the forum.
- name: 📖 Documentation Issue
url: https://github.com/umbraco/UmbracoDocs/issues
about: Documentation issues should be reported on the Umbraco documentation repository.
- name: 🔐 Security Issue
url: https://umbraco.com/trust-center/security-and-umbraco/how-to-report-a-vulnerability-in-umbraco/
url: https://umbraco.com/about-us/trust-center/security-and-umbraco/how-to-report-a-vulnerability-in-umbraco/
about: Discovered a Security Issue in Umbraco?
+20 -43
View File
@@ -1,63 +1,40 @@
# [Umbraco CMS](https://umbraco.com)
# [Umbraco CMS](https://umbraco.com) &middot; [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](../LICENSE.md) [![Build status](https://umbraco.visualstudio.com/Umbraco%20Cms/_apis/build/status/Cms%208%20Continuous?branchName=v8/contrib)](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md) [![Twitter](https://img.shields.io/twitter/follow/umbraco.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=umbraco)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](../LICENSE.md)
[![NuGet Version](https://img.shields.io/nuget/v/Umbraco.Cms)](https://www.nuget.org/packages/Umbraco.Cms)
[![Build status](https://img.shields.io/azure-devops/build/umbraco/Umbraco%2520Cms/301?logo=azurepipelines&label=Azure%20Pipelines)](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=301)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
[![Forum](https://img.shields.io/badge/help-forum-blue)](https://forum.umbraco.com)
[![Chat about Umbraco on Discord](https://img.shields.io/discord/869656431308189746?logo=discord&logoColor=fff)](https://discord.gg/umbraco)
![Mastodon Follow](https://img.shields.io/mastodon/follow/110661369750014952?domain=https%3A%2F%2Fumbracocommunity.social)
### Umbraco is a free and open source .NET content management system. Our mission is to help you deliver delightful digital experiences by making Umbraco friendly, simpler and social.
Umbraco is the friendliest, most flexible and fastest growing ASP.NET CMS, and used by more than 500,000 websites worldwide. Our mission is to help you deliver delightful digital experiences by making Umbraco friendly, simpler and social.
Learn more at [umbraco.com](https://umbraco.com)
<p align="center">
<img src="img/logo.png" alt="Umbraco Logo" />
<img src="img/logo.png" alt="Umbraco Logo" />
</p>
## <a name="install"></a>Looking to install Umbraco?
See the official [Umbraco website](https://umbraco.com) for an introduction, core mission and values of the product and team behind it.
You can get started using the following commands on Windows, Linux and MacOS (after installing the [.NET Runtime and SDK](https://docs.umbraco.com/umbraco-cms/fundamentals/setup/requirements)):
- [Getting Started](#getting-started)
- [Documentation](#documentation)
- [Community](#join-the-umbraco-community)
- [Contributing](#contributing)
```
dotnet new install Umbraco.Templates
dotnet new umbraco --name MyProject
cd MyProject
dotnet run
```
Please also see our [Code of Conduct](CODE_OF_CONDUCT.md).
## Getting Started
[Umbraco Cloud](https://umbraco.com/cloud) is the easiest and fastest way to use Umbraco yet, with full support for all your custom .NET code and integrations. You're up and running in less than a minute, and your life will be made easier with automated upgrades and a built-in deployment engine. We offer a free 14-day trial, no credit card needed.
If you want to DIY, then you can [download Umbraco]((https://our.umbraco.com/download)) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Cloud, but you'll need to find a place to host it yourself, and handling deployments and upgrades will be all up to you.
## Documentation
Our [comprehensive documentation](https://docs.umbraco.com/umbraco-cms) takes you from the fundamentals on how to start with Umbraco to deploying it to production.
The documentation for Umbraco CMS can be found [on Our Umbraco](https://our.umbraco.com/documentation/). The source for the Umbraco docs is [open source as well](https://github.com/umbraco/UmbracoDocs) and we're happy to look at your documentation contributions.
Some important documentation links to get you started:
## Join the Umbraco community
- [Installing Umbraco CMS](https://docs.umbraco.com/umbraco-cms/fundamentals/setup/install)
- [Getting to know Umbraco](https://docs.umbraco.com/umbraco-cms/fundamentals/get-to-know-umbraco)
- [Tutorials for creating a basic website and customizing the editing experience](https://docs.umbraco.com/umbraco-cms/tutorials/overview)
Our friendly community is available 24/7 at the community hub, we call ["Our Umbraco"](https://our.umbraco.com/). Our Umbraco features forums for questions and answers, documentation, downloadable plugins for Umbraco, and a rich collection of community resources.
## Backoffice Preview
Besides "Our", we all support each other also via Twitter: [Umbraco HQ](https://twitter.com/umbraco), [Release Updates](https://twitter.com/umbracoproject), [#umbraco](https://twitter.com/hashtag/umbraco)
Want to see the latest backoffice UI in action? Check out our live preview:
**[backofficepreview.umbraco.com](https://backofficepreview.umbraco.com/)**
This preview is automatically deployed from the main branch and showcases the latest backoffice features and improvements. It runs from mock data and persistent edits are not supported.
## Get help
If you need a bit of feedback while building your Umbraco projects, we are [chatty on Discord](https://discord.umbraco.com). Our Discord server serves as a social space for all Umbracians. If you have any questions or need some help with a problem, head over to our [dedicated forum](https://forum.umbraco.com/) where the Umbraco Community will be happy to help.
## Looking to contribute back to Umbraco?
You came to the right place! Our GitHub repository is available for all kinds of contributions:
- [Create a bug report](https://github.com/umbraco/Umbraco-CMS/issues)
- [Create a feature request](https://github.com/umbraco/Umbraco-CMS/discussions)
## Contributing
Umbraco is contribution-focused and community-driven. If you want to contribute back to the Umbraco source code, please check out our [guide to contributing](CONTRIBUTING.md).
### Tip: You should not run Umbraco from source code found here. Umbraco is extremely extensible and can do whatever you need. Instead, [install Umbraco as noted above](#looking-to-install-umbraco) and then [extend it any way you want to](https://docs.umbraco.com/umbraco-cms/extending/).
-30
View File
@@ -1,30 +0,0 @@
# Bellissima release instructions
## Build
> _See internal documentation on the build/release workflow._
## GitHub Release Notes
To generate release notes on GitHub.
- Go to the [**Releases** area](https://github.com/umbraco/Umbraco.CMS.Backoffice/releases)
- Press the [**"Draft a new release"** button](https://github.com/umbraco/Umbraco.CMS.Backoffice/releases/new)
- In the combobox for "Choose a tag", expand then select or enter the next version number, e.g. `release-14.2.0`
- If the tag does not already exist, an option labelled "Create new tag: release-14.2.0 on publish" will appear, select that option
- In the combobox for "Target: main", expand then select the release branch for the next version, e.g. `release/14.2`
- In the combobox for "Previous tag: auto":
- If the next release is an RC, then you can leave as `auto`
- Otherwise, select the previous stable version, e.g. `release-14.1.1`
- Press the **"Generate release notes"** button, this will populate the main textarea
- Change the title to match the version, e.g. `14.2.0`
- Check the details, view in the "Preview" tab
- What type of release is this?
- If it's an RC, then check "Set as a pre-release"
- If it's stable, then check "Set as the latest release"
- Once you're happy with the contents and ready to save...
- If you need more time to review, press the **"Save draft"** button and you can come back to it later
- If you are ready to make the release notes public, then press **"Publish release"** button! :tada:
> If you're curious about how the content is generated, take a look at the `release.yml` configuration:
> https://github.com/umbraco/Umbraco.CMS.Backoffice/blob/main/.github/release.yml
+25
View File
@@ -0,0 +1,25 @@
# Review process
You're an awesome person and have sent us your contribution in the form of a pull request! It's now time to relax for a bit and wait for our response.
In order to set some expectations, here's what happens next.
## Review process
You will get an initial reply within 48 hours (workdays) to acknowledge that weve seen your PR and well pick it up as soon as we can.
You will get feedback within at most 14 days after opening the PR. Youll most likely get feedback sooner though. Then there are a few possible outcomes:
- Your proposed change is awesome! We merge it in and it will be included in the next minor release of Umbraco
- If the change is a high priority bug fix, we will cherry-pick it into the next patch release as well so that we can release it as soon as possible
- Your proposed change is awesome but needs a bit more work, well give you feedback on the changes wed like to see
- Your proposed change is awesome but.. not something were looking to include at this point. Well close your PR and the related issue (well be nice about it!)
## Are you still available?
We understand you have other things to do and can't just drop everything to help us out.
So if were asking for your help to improve the PR well wait for two weeks to give you a fair chance to make changes. Well ask for an update if we dont hear back from you after that time.
If we dont hear back from you for 4 weeks, well close the PR so that it doesnt just hang around forever. Youre very welcome to re-open it once you have some more time to spend on it.
There will be times that we really like your proposed changes and well finish the final improvements wed like to see ourselves. You still get the credits and your commits will live on in the git repository.
-21
View File
@@ -1,21 +0,0 @@
# GitHub CodeSpaces
Umbraco source code can be edited inside the browser with VSCode and CodeSpaces.
This development environment comes with all the tools you need to build Umbraco source code.
## Debugging and Running
From VSCode browse to the Run and Debug section and then click the green button. This will build the Umbraco source code and attach a debugger and launch the site.
## Default Umbraco credentials
Username: test@umbraco.com
Password: password1234
## Test Email Server
A SMTP4Dev instance for testing email is available on port 5000.
## SQLite Database
The SQLite extension is preinstalled and allows you to open, query, edit the data inside the Umbraco SQLite database for ease of use.
+12 -7
View File
@@ -1,9 +1,14 @@
name: "CodeQL config"
on:
push:
branches: [v8/contrib,v8/dev]
paths-ignore:
- node_modules
- Umbraco.TestData
- Umbraco.Tests
- Umbraco.Tests.AcceptanceTest
- Umbraco.Tests.Benchmarks
- bin
- build.tmp
paths:
- src
paths-ignore:
- '**/node_modules'
- 'src/Umbraco.Web.UI/wwwroot'
- 'src/Umbraco.Cms.StaticAssets/wwwroot'
- src
-230
View File
@@ -1,230 +0,0 @@
# Contribution Guidelines
## Thoughts, links, and questions
In the high probability that you are porting something from angular JS then here are a few helpful tips for using Lit:
Here is the LIT documentation and playground: [https://lit.dev](https://lit.dev)
### What is the process of contribution?
- Read the [README](README.md) to learn how to get the project up and running
- Find an issue marked as [community/up-for-grabs](https://github.com/umbraco/Umbraco.CMS.Backoffice/issues?q=is%3Aissue+is%3Aopen+label%3Acommunity%2Fup-for-grabs) - note that some are also marked [good first issue](https://github.com/umbraco/Umbraco.CMS.Backoffice/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) which indicates they are simple to get started on
- Umbraco HQ owns the Management API on the backend, so features can be worked on in the frontend only when there is an API, or otherwise if no API is required
- A contribution should be made in a fork of the repository
- Once a contribution is ready, a pull request should be made to this repository and HQ will assign a reviewer
- A pull request should always indicate what part of a feature it tries to solve, i.e. does it close the targeted issue (if any) or does the developer expect Umbraco HQ to take over
## Contributing in general terms
A lot of the UI has already been migrated to the new backoffice. Generally speaking, one would find a feature on the projects board, locate the UI in the old backoffice (v11 is fine), convert it to Lit components using the UI library, put the business logic into a store/service, write tests, and make a pull request.
We are also very keen to receive contributions towards **documentation, unit testing, package development, accessibility, and just general testing of the UI.**
## The Management API
The management API is the colloquial term used to describe the new backoffice API. It is built as a .NET Web API, has a Swagger endpoint (/umbraco/swagger), and outputs an OpenAPI v3 schema, that the frontend consumes.
The frontend has an API formatter that takes the OpenAPI schema file and converts it into a set of TypeScript classes and interfaces.
**Current schema for API:**
[https://raw.githubusercontent.com/umbraco/Umbraco-CMS/v13/dev/src/Umbraco.Cms.Api.Management/OpenApi.json](https://raw.githubusercontent.com/umbraco/Umbraco-CMS/v15/dev/src/Umbraco.Cms.Api.Management/OpenApi.json)
**How to convert it:**
- Run `npm run generate:server-api`
## A contribution example
### Example: Published Cache Status Dashboard
![Published Status Dashboard](/.github/img/contributing/published-cache-status-dashboard.png)
### Boilerplate (example using Lit)
Links for Lit examples and documentation:
- [https://lit.dev](https://lit.dev)
- [https://lit.dev/docs/](https://lit.dev/docs/)
- [https://lit.dev/playground/](https://lit.dev/playground/)
### Functionality
**HTML**
The simplest approach is to copy over the HTML from the old backoffice into a new Lit element (check existing elements in the repository, e.g. if you are working with a dashboard, then check other dashboards, etc.). Once the HTML is inside the `render` method, it is often enough to simply replace `<umb-***>` elements with `<uui-***>` and replace a few of the attributes. In general, we try to build as much UI with Umbraco UI Library as possible.
**Controller**
The old AngularJS controllers will have to be converted into modern TypeScript and will have to use our new services and stores. We try to abstract as much away as possible, and mostly you will have to make API calls and let the rest of the system handle things like error handling and so on. In the case of this dashboard, we only have a few GET and POST requests. Looking at the new Management API, we find the PublishedCacheService, which is the new API controller to serve data to the dashboard.
To make the first button work, which simply just requests a new status from the server, we must make a call to `PublishedCacheService.getPublishedCacheStatus()`. An additional thing here is to wrap that in a friendly function called `tryExecuteAndNotify`, which is something we make available to developers to automatically handle the responses coming from the server and additionally use the Notifications to notify of any errors:
```typescript
import { tryExecuteAndNotify } from '@umbraco-cms/backoffice/resources';
import { PublishedCacheService } from '@umbraco-cms/backoffice/external/backend-api';
private _getStatus() {
const { data: status } = await tryExecuteAndNotify(this, PublishedCacheService.getPublishedCacheStatus());
if (status) {
// we now have the status
console.log(status);
}
}
```
### State (buttons, etc)
It is a good idea to make buttons indicate a loading state when awaiting an API call. All `<uui-button>` support the `.state` property, which you can set around API calls:
```typescript
@state()
private _buttonState: UUIButtonState = undefined;
private _getStatus() {
this._buttonState = 'waiting';
[...await...]
this._buttonState = 'success';
}
```
## Making the dashboard visible
### Add to internal manifests
All items are declared in a `manifests.ts` file, which is located in each section directory.
To declare the Published Cache Status Dashboard as a new manifest, we need to add the section as a new json object that would look like this:
```typescript
{
type: 'dashboard',
alias: 'Umb.Dashboard.PublishedStatus',
name: 'Published Status Dashboard',
elementName: 'umb-dashboard-published-status',
element: () => import('./published-status/dashboard-published-status.element.js'),
weight: 200,
meta: {
label: 'Published Status',
pathname: 'published-status',
},
conditions: [
{
alias: UMB_SECTION_ALIAS_CONDITION_ALIAS,
match: 'Umb.Section.Settings',
},
],
},
```
Lets go through each of these properties…
- Type: can be one of the following:
- section - examples include: `Content`, `Media`
- dashboard - a view within a section. Examples include: the welcome dashboard
- propertyEditorUi
- editorView
- propertyAction
- tree
- editor
- treeItemAction
- Alias: is the unique key used to identify this item.
- Name: is the human-readable name for this item.
- ElementName: this is the customElementName declared on the element at the top of the file i.e
```typescript
@customElement('umb-dashboard-published-status')
```
- Js: references a function call to import the file that the element is declared within
- Weight: allows us to specify the order in which the dashboard will be displayed within the tabs bar
- Meta: allows us to reference additional data - in our case, we can specify the label that is shown in the tabs bar and the pathname that will be displayed in the URL
- Conditions: allows us to specify the conditions that must be met for the dashboard to be displayed. In our case, we are specifying that the dashboard will only be displayed within the Settings section
## API mock handlers
Running the app with `npm run dev`, you will quickly notice the API requests turn into 404 errors. To hit the API, we need to add a mock handler to define the endpoints that our dashboard will call. In the case of the Published Cache Status section, we have several calls to work through. Lets start by looking at the call to retrieve the current status of the cache:
![Published Status Dashboard](/.github/img/contributing/status-of-cache.png)
From the existing functionality, we can see that this is a string message that is received as part of a `GET` request from the server.
So to define this, we must first add a handler for the Published Status called `published-status.handlers.ts` within the mocks/domains folder. In this file we will have code that looks like the following:
```typescript
const { rest } = window.MockServiceWorker;
import { umbracoPath } from "@umbraco-cms/backoffice/utils";
export const handlers = [
rest.get(umbracoPath("/published-cache/status"), (_req, res, ctx) => {
return res(
// Respond with a 200 status code
ctx.status(200),
ctx.json<string>(
"Database cache is ok. ContentStore contains 1 item and has 1 generation and 0 snapshot. MediaStore contains 5 items and has 1 generation and 0 snapshot."
)
);
}),
];
```
This is defining the `GET` path that we will call through the resource: `/published-cache/status`
It returns a `200 OK` response and a string value with the current “status” of the published cache for us to use within the element
An example `POST` is similar. Lets take the “Refresh status” button as an example:
![Published Status Dashboard](/.github/img/contributing/refresh-status.png)
From our existing functionality, we can see that this makes a `POST` call to the server to prompt a reload of the published cache. So we would add a new endpoint to the mock handler that would look like:
```typescript
rest.post(umbracoPath('/published-cache/reload'), async (_req, res, ctx) => {
return res(
// Simulate a 1 second delay for the benefit of the UI
ctx.delay(1000)
// Respond with a 201 status code
ctx.status(201)
);
})
```
Which is defining a new `POST` endpoint that we can add to the core API fetcher using the path `/published-cache/reload`.
This call returns a simple `OK` status code and no other object.
## Storybook stories
We try to make good Storybook stories for new components, which is a nice way to work with a component in an isolated state. Imagine you are working with a dialog on page 3 and have to navigate back to that every time you make a change - this is now eliminated with Storybook as you can just make a story that displays that step. Storybook can only show one component at a time, so it also helps us to isolate view logic into more and smaller components, which in turn are more testable.
In-depth: [https://storybook.js.org/docs/web-components/get-started/introduction](https://storybook.js.org/docs/web-components/get-started/introduction)
Reference: [https://ambitious-stone-0033b3603.1.azurestaticapps.net/](https://ambitious-stone-0033b3603.1.azurestaticapps.net/)
- Locally: `npm run storybook`
For Umbraco UI stories, please navigate to [https://uui.umbraco.com/](https://uui.umbraco.com/)
## Testing
There are two testing tools on the backoffice: unit testing and end-to-end testing.
### Unit testing
We are using a tool called Web Test Runner which spins up a bunch of browsers using Playwright with the well-known jasmine/chai syntax. It is expected that any new component/element has a test file named “&lt;component>.test.ts”. It will automatically be picked up and there are a set of standard tests we apply to all components, which checks that they are registered correctly and they pass accessibility testing through Axe.
Working with playwright: [https://playwright.dev/docs/intro](https://playwright.dev/docs/intro)
## Putting it all together
When we are finished with the dashboard we will hopefully have something akin to this [real-world example of the actual dashboard that was migrated](https://github.com/umbraco/Umbraco.CMS.Backoffice/tree/main/src/backoffice/settings/dashboards/published-status).
-54
View File
@@ -1,54 +0,0 @@
## Before you start
### Code of Conduct
This project and everyone participating in it, is governed by the [our Code of Conduct][code of conduct].
### What can I contribute?
We categorise pull requests (PRs) into two categories:
| PR type | Definition |
| --------- | ------------------------------------------------------------ |
| Small PRs | Bug fixes and small improvements - can be recognized by seeing a small number of changes and possibly a small number of new files. |
| Large PRs | New features and large refactorings - can be recognized by seeing a large number of changes, plenty of new files, updates to package manager files (NuGets packages.config, NPMs packages.json, etc.). |
Were usually able to handle small PRs pretty quickly. A community volunteer will do the initial review and flag it for Umbraco HQ as “community tested”. If everything looks good, it will be merged pretty quickly [as per the described process][review process].
We would love to follow the same process for larger PRs but this is not always possible due to time limitations and priorities that need to be aligned. We dont want to put up any barriers, but this document should set the correct expectations.
Not all changes are wanted, so on occasion we might close a PR without merging it but if we do, we will give you feedback why we can't accept your changes. **So make sure to [talk to us before making large changes][making larger changes]**, so we can ensure that you don't put all your hard work into something we would not be able to merge.
#### Making larger changes
[making larger changes]: #making-larger-changes
Please make sure to describe your larger ideas in an [issue (bugs)][issues] or [discussion (new features)][discussions], it helps to put in mock up screenshots or videos. If the change makes sense for HQ to include in Umbraco CMS we will leave you some feedback on how wed like to see it being implemented.
If a larger pull request is encouraged by Umbraco HQ, the process will be similar to what is described in the small PRs process above, we strive to feedback within 14 days. Finalizing and merging the PR might take longer though as it will likely need to be picked up by the development team to make sure everything is in order. Well keep you posted on the progress.
#### Pull request or package?
[pr or package]: #pull-request-or-package
If you're unsure about whether your changes belong in the core Umbraco CMS or if you should turn your idea into a package instead, make sure to [talk to us][making larger changes].
If it doesnt fit in CMS right now, we will likely encourage you to make it into a package instead. A package is a great way to check out popularity of a feature, learn how people use it, validate good usability and fix bugs. Eventually, a package could "graduate" to be included in the CMS.
#### Ownership and copyright
It is your responsibility to make sure that you're allowed to share the code you're providing us. For example, you should have permission from your employer or customer to share code.
Similarly, if your contribution is copied or adapted from somewhere else, make sure that the license allows you to reuse that for a contribution to Umbraco-CMS.
If you're not sure, leave a note on your contribution and we will be happy to guide you.
When your contribution has been accepted, it will be [MIT licensed][MIT license] from that time onwards.
[MIT license]: ../LICENSE.md "Umbraco's license declaration"
[issues]: https://github.com/umbraco/Umbraco-CMS/issues
[discussions]: https://github.com/umbraco/Umbraco-CMS/discussions
-28
View File
@@ -1,28 +0,0 @@
### The Core Collaborators team
[Core collabs]: #the-core-collaborators-team
The Core Contributors team consists of one member of Umbraco HQ, [Sebastiaan][Sebastiaan], who gets assistance from the following community members who have committed to volunteering their free time:
- [Busra Sengul][Busra Sengul]
- [Emma Garland][Emma Garland]
- [George Bidder][George Bidder]
- [Jason Elkin][Jason Elkin]
- [Laura Neto][Laura Neto]
- [Kyle Eck][Kyle Eck]
- [Michael Latouche][Michael Latouche]
- [Sebastiaan][Sebastiaan]
These wonderful people aim to provide you with a reply to your PR, review and test out your changes and on occasions, they might ask more questions. If they are happy with your work, they'll let Umbraco HQ know by approving the PR. HQ will have final sign-off and will check the work again before it is merged.
<!-- External -->
[Busra Sengul]: https://github.com/busrasengul "Busra's GitHub profile"
[Emma Garland]: https://github.com/emmagarland "Emma's GitHub profile"
[George Bidder]: https://github.com/georgebid "George's GitHub profile"
[Jason Elkin]: https://github.com/jasonelkin "Jason's GitHub profile"
[Kyle Eck]: https://github.com/teckspeed "Kyle's GitHub profile"
[Laura Neto]: https://github.com/lauraneto "Laura's GitHub profile"
[Michael Latouche]: https://github.com/mikecp "Michael's GitHub profile"
[Sebastiaan]: https://github.com/nul800sebastiaan "Sebastiaan's GitHub profile"
-69
View File
@@ -1,69 +0,0 @@
## Creating a pull request
Exciting! You're ready to show us your changes.
We recommend you to [sync with our repository][sync fork] before you submit your pull request. That way, you can fix any potential merge conflicts and make our lives a little bit easier.
GitHub will have picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go.
![Create a pull request](img/createpullrequest.png)
We like to use [git flow][git flow] as much as possible, but don't worry if you are not familiar with it. The most important thing you need to know is that when you fork the Umbraco repository, the default branch is set to `main`. This is the branch you should be targeting.
We welcome PRs for features and bugfixes for different versions according to the [published support and EOL schedule][support-and-eol].
We don't have rules for naming PRs - so name them as you prefer. At HQ we do have a best practice on clear and concise PR naming, so if you would like to use the format feel free to do so.
Our convention of doing it is:
_Area: Description (closes #IssueID)_
1. Start by specifying the area. Fx the feature name(UFM, Tiptap etc.) or specific section (migrations, relations, segmentation).
2. In your description, where applicable, mention type of PR (Build, Bump, Fix, Refactor etc.).
4. Good practise is to make sure you describe specifically the change and/or impact of change.<br>
Example: Writing "Extension Insights: Fixes CSS alignment" instead of "Fixed issue".
6. Add (closes #IssueID) behind description, if your PR resolves an issue.
That's it!
## The review process
[review process]: #the-review-process
You've sent us your contribution - congratulations! Now what?
The [Core Collaborators team][Core collabs] can now start reviewing your proposed changes and give you feedback on them. If it's not perfect, we'll either fix up what we need or we can request that you make some additional changes.
You will get an initial automated reply from our [Friendly Umbraco Robot, Umbrabot][Umbrabot], to acknowledge that weve seen your PR and well pick it up as soon as we can. You can take this opportunity to double check everything is in order based off the handy checklist Umbrabot provides.
You will get feedback as soon as the [Core Collaborators team][Core collabs] can after opening the PR. Youll most likely get feedback within a couple of weeks. Then there are a few possible outcomes:
- Your proposed change is awesome! We merge it in and it will be included in the next minor release of Umbraco
- If the change is a high priority bug fix, we will cherry-pick it into the next patch release as well so that we can release it as soon as possible
- Your proposed change is awesome but needs a bit more work, well give you feedback on the changes wed like to see
- Your proposed change is awesome but... not something were looking to include at this point. Well close your PR and the related issue (well be nice about it!). See [making larger changes][making larger changes] and [pull request or package?][pr or package]
### Dealing with requested changes
If you make the corrections we ask for in the same branch and push them to your fork again, the pull request automatically updates with the additional commit(s) so we can review it again. If all is well, we'll merge the code and your commits are forever part of Umbraco!
#### No longer available?
We understand you have other things to do and can't just drop everything to help us out.
So if were asking for your help to improve the PR well wait for two weeks to give you a fair chance to make changes. Well ask for an update if we dont hear back from you after that time.
If we dont hear back from you for 4 weeks, well close the PR so that it doesnt just hang around forever. Youre very welcome to re-open it once you have some more time to spend on it.
There will be times that we really like your proposed changes and well finish the final improvements wed like to see ourselves. You still get the credits and your commits will live on in the git repository.
[ Umbrabot ]: https://github.com/umbrabot
[git flow]: https://jeffkreeftmeijer.com/git-flow/ "An explanation of git flow"
[making larger changes]: contributing-before-you-start.md#making-large-changes
[pr or package]: contributing-before-you-start.md#pull-request-or-package
[Core collabs]: contributing-core-collabs-team.md
[support-and-eol]: https://umbraco.com/products/knowledge-center/long-term-support-and-end-of-life/
-96
View File
@@ -1,96 +0,0 @@
## Finding your first issue
Umbraco HQ will regularly mark newly created issues on the issue tracker with [the `community/up-for-grabs` tag][up for grabs issues]. This means that the proposed changes are wanted in Umbraco but the HQ does not have the time to make them at this time. In adding the label we will endeavour to provide some guidelines on how to go about the implementation, such that it aligns with the project. We encourage anyone to pick them up and help out.
You don't need to restrict yourselves to issues that are specifically marked as "up for grabs" though. If you are running into a bug you have reported or found on the [issue tracker][issue tracker], it's not necessary to wait for HQ response. Feel free to dive in and try to provide a fix, raising questions as you need if you have concerns about the modifications necessary to resolve the problem.
If you do start working on something, make sure to leave a small comment on the issue saying something like: "I'm working on this". That way other people stumbling upon the issue know they don't need to pick it up, someone already has.
## Making your changes
Great question! The short version goes like this:
1. **Fork**
Create a fork of [`Umbraco-CMS` on GitHub][Umbraco CMS repo]
![Fork the repository](img/forkrepository.png)
1. **Clone**
When GitHub has created your fork, you can clone it in your favorite Git tool
![Clone the fork](img/clonefork.png)
1. **Switch to the correct branch**
Switch to the `main` branch
1. **Build**
Build your fork of Umbraco locally as described in the build documentation: you can [debug with Visual Studio Code][build - debugging with code] or [with Visual Studio][build - debugging with vs].
1. **Branch**
Create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-12345`. This means it's a temporary branch for the particular issue you're working on, in this case issue number `12345`. Don't commit to `main`, create a new branch first.
1. **Change**
Make your changes, experiment, have fun, explore and learn, and don't be afraid. We welcome all contributions and will [happily give feedback][questions].
1. **Commit and push**
Done? Yay! 🎉
Remember to commit to your new `temp` branch, and don't commit to `main`. Then you can push the changes up to your fork on GitHub.
#### Keeping your Umbraco fork in sync with the main repository
[sync fork]: #keeping-your-umbraco-fork-in-sync-with-the-main-repository
Once you've already got a fork and cloned your fork locally, you can skip steps 1 and 2 going forward. Just remember to keep your fork up to date before making further changes.
To sync your fork with this original one, you'll have to add the upstream url. You only have to do this once:
```
git remote add upstream https://github.com/umbraco/Umbraco-CMS.git
```
Then when you want to get the changes from the main repository:
```
git fetch upstream
git rebase upstream/main
```
In this command we're syncing with the `main` branch, but you can of course choose another one if needed.
[More information on how this works can be found on the thoughtbot blog.][sync fork ext]
#### Style guide
To be honest, we don't like rules very much. We trust you have the best of intentions and we encourage you to create working code. If it doesn't look perfect then we'll happily help clean it up.
That said, the Umbraco development team likes to follow the hints that ReSharper gives us (no problem if you don't have this installed) and we've added a `.editorconfig` file so that Visual Studio knows what to do with whitespace, line endings, etc.
#### Questions?
[questions]: #questions
You can get in touch with [the core contributors team][core collabs] in multiple ways; we love open conversations and we are a friendly bunch. No question you have is stupid. Any question you have usually helps out multiple people with the same question. Ask away:
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward.
- If you want to ask questions on some code you've already written you can create a draft pull request, [detailed in a GitHub blog post][draft prs].
- Unsure where to start? Did something not work as expected? Try leaving a note in the [forum][forum]. The team monitors that one closely, so one of us will be on hand and ready to point you in the right direction.
<!-- Local -->
[build - debugging with vs]: BUILD.md#debugging-with-visual-studio "Details on building and debugging Umbraco with Visual Studio"
[build - debugging with code]: BUILD.md#debugging-with-vs-code "Details on building and debugging Umbraco with Visual Studio Code"
[sync fork ext]: http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated "Details on keeping a git fork updated"
[draft prs]: https://github.blog/2019-02-14-introducing-draft-pull-requests/ "Github's blog post providing details on draft pull requests"
[forum]: https://forum.umbraco.com/
[Umbraco CMS repo]: https://github.com/umbraco/Umbraco-CMS
[up for grabs issues]: https://github.com/umbraco/Umbraco-CMS/issues?q=is%3Aissue+is%3Aopen+label%3Acommunity%2Fup-for-grabs
[issue tracker]: https://github.com/umbraco/Umbraco-CMS/issues
-223
View File
@@ -1,223 +0,0 @@
# **Contributing to Localization in the Backoffice**
Do you want to help keep our translations accurate and up to standard? 🌍✨
Your input makes a real difference! By reviewing, refining, or suggesting improvements, you ensure that our translations remain clear, consistent, and user-friendly for everyone.
## **How Can I Contribute?**
To contribute to localization in the Backoffice, follow this step-by-step guide:
### **1. Change the Language in Backoffice**
1. Open the Backoffice, click on your profile icon in the top-right corner, and select "Edit."
![Menubar profile image](/.github/img/contributing/ProfileImage.png "Menubar profile image")
![Edit button inside profile](/.github/img/contributing/editBtn.png "Edit button inside profile")
2. Under "UI Culture," select the language you want to review from the dropdown menu.
![Dropdown of languages in Umbraco](/.github/img/contributing/uiCulture.png "Dropdown of languages in Umbraco")
### **2. Find a Translation Error**
1. Navigate through the Backoffice and check if everything is translated correctly.
2. When you find a translation error, right-click on it and select "Inspect."
3. Look for the nearest element that starts with `umb-` and has a name indicating something specific to the given location.
**Example:**
* The closest parent element should be specific, such as `umb-document-type-workspace-view-settings` instead of a generic element like `umb-property-layout.`
### **3. Find the Code in VS Code**
1. Open VS Code and search for the nearest `umb-` element you identified.
![Search for nearest umb element in code](/.github/img/contributing/searchInVsCode.png "Search for nearest umb element in code")
2. Scroll down to find `render() {` and look for the element label that needs updating.
![Find render and label in code](/.github/img/contributing/renderCode.png "Find render and label in code")
3. If the label is hardcoded, it must be updated.
**Example:**
`label="Vary by culture"`
### **4. Find the Correct Translation**
1. Open the `en.ts` or `en-us.ts` file and search for relevant keywords. \
\
**Example:**
* If the text is "Vary by culture," search for `vary`, `culture`, or `Vary by culture`.
2. Once you find the translation, take the element name and search for it in the target language file (e.g., `da-dk.ts` for Danish).
![Search for translation in language files](/.github/img/contributing/searchingThroughLanguageFiles.png "Search for translation in language files")
3. If a translation exists, insert it into the label element found earlier.
### **5. Insert the Translation**
To display the new translation correctly, insert the following code inside the label element:
`${this.localize.term('action_key')}`
Replace `action_key` with the correct translation key.
**Example:**
`${this.localize.term('contentTypeEditor_allowVaryByCulture')}`
![Localization code snippet](/.github/img/contributing/localizationCodeSnippetInCode.png "Localization code snippet")
Save the changes and return to the Backoffice to see the update.
![Changes in backoffice after changes in code](/.github/img/contributing/changedBackofficeAfterLocalization.png "Changes in backoffice after changes in code")
### **6. Commit and Push**
1. Commit your changes to a new temporary branch (avoid committing directly to `main`).
2. Push the changes to your fork on GitHub.
### **7. Create a Pull Request**
1. In your forked repository on GitHub (`https://github.com/[YourUsername]/Umbraco-CMS`), a banner will appear stating that you pushed a new branch.
2. Click the button to create a pull request and follow the instructions.
## **I Cant Find the Correct Translation**
If you cant find the translation you need, it may not exist yet. In this case, you can create a new action with related keys.
### **1. Ensure It Doesnt Already Exist**
Search thoroughly in `en.ts` or `en-us.ts` for all relevant keywords.
### **2. Create an Action**
1. Choose a meaningful name for the action to avoid confusion. \
\
**Example:** Translation for the Data Type "Color Picker."
* **Good name:** `colorPickerConfigurations`
* **Bad name:** `colorpicker`
2. A specific action name prevents unnecessarily long key names.
3. Define the action:
### **3. Create Keys**
1. Use clear and descriptive key names. \
\
**Example:**
* **Good name:** `colorsTitle`
* **Bad name:** `colors`
2. Add the necessary keys inside the action with proper translations.
![Action and related Keys in language files](/.github/img/contributing/actionAndKeys.png "Action and related Keys in language files")
## **I Cant Find a <code>render()</code> Code in VS Code**
In some cases, such as Data Types, the label might not be inside `render()`. Instead, it may be in a manifest file.
### 1. Search for the Text
Copy the text from the Backoffice and search for it in the code.
### 2. Open the Manifest File
Once you find the relevant manifest file, open it to confirm youre in the right place.
### 3. Change the Label
In Markdown files, localization is slightly different. Instead of:
`${this.localize.term('action_key')}`
Use: `#action_key`
**Example:**
`#colorPickerConfigurations_showLabelTitle`
### 4. Change the Description
For descriptions in Markdown files, use:
`{umbLocalize: action_key}`
**Example:**
`{umbLocalize: colorPickerConfigurations_showLabelDescription}`
### 5. Save and Verify
Once all changes are made, your manifest should look something like this:
![Localization changes to manifest files](/.github/img/contributing/finishedManifestAfterLocalizatonChanges.png "Localization changes to manifest files")
---
### Thank you
Following these steps ensures that the Umbraco Backoffice remains accessible and user-friendly in all supported languages. Thanks for contributing! 🎉
@@ -1,10 +0,0 @@
## Coding not your thing? Or want more ways to contribute?
This document covers contributing to the codebase of the CMS but [the community site has plenty of inspiration for other ways to get involved.][get involved]
If you don't feel you'd like to make code changes here, you can visit our [documentation repository][docs repo] and use your experience to contribute to making the docs we have, even better.
We also encourage community members to feel free to comment on others' pull requests and issues - the expertise we have is not limited to the Core Collaborators and HQ. So, if you see something on the issue tracker or pull requests you feel you can add to, please don't be shy.
[get involved]: https://community.umbraco.com/get-involved/
[docs repo]: https://github.com/umbraco/UmbracoDocs
-18
View File
@@ -1,18 +0,0 @@
## Unwanted changes
While most changes are welcome, there are certain types of changes that are discouraged and might get your pull request refused.
Of course this will depend heavily on the specific change, but please take the following examples in mind.
- **Breaking changes (code and/or behavioral) 💥** - sometimes it can be a bit hard to know if a change is breaking or not. Fortunately, if it relates to code, the build will fail and warn you.
- **Large refactors 🤯** - the larger the refactor, the larger the probability of introducing new bugs/issues.
- **Changes to obsolete code and/or property editors ✍️**
- **Adding new config options 🦾** - while having more flexibility is (most of the times) better, having too many options can also become overwhelming/confusing, especially if there are other (good/simple) ways to achieve it.
- **Whitespace changes 🫥** - while some of our files might not follow the formatting/whitespace rules (mostly old ones), changing several of them in one go would cause major merge conflicts with open pull requests or other work in progress. Do feel free to fix these when you are working on another issue/feature and end up "touching" those files!
- **Adding new extension/helper methods ✋** - keep in mind that more code also means more to maintain, so if a helper is only meaningful for a few, it might not be worth adding it to the core.
While these are only a few examples, it is important to ask yourself these questions before making a pull request:
- How many will benefit from this change?
- Are there other ways to achieve this? And if so, how do they compare?
- How maintainable is the change?
- What would be the effort to test it properly?
- Do the benefits outweigh the risks?
-1
View File
@@ -1 +0,0 @@
The full development guide for this repository lives in [CLAUDE.md](../CLAUDE.md). Please read that file for complete instructions on architecture, build steps, testing, branching conventions, and coding patterns.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

-3
View File
@@ -1,3 +0,0 @@
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16">
<path fill-rule="evenodd" d="M2 4a1 1 0 100-2 1 1 0 000 2zm3.75-1.5a.75.75 0 000 1.5h8.5a.75.75 0 000-1.5h-8.5zm0 5a.75.75 0 000 1.5h8.5a.75.75 0 000-1.5h-8.5zm0 5a.75.75 0 000 1.5h8.5a.75.75 0 000-1.5h-8.5zM3 8a1 1 0 11-2 0 1 1 0 012 0zm-1 6a1 1 0 100-2 1 1 0 000 2z" fill="#57606A"></path>
</svg>

Before

Width:  |  Height:  |  Size: 462 B

-38
View File
@@ -1,38 +0,0 @@
# .github/release.yml
changelog:
exclude:
labels:
- ignore-for-release
- duplicate
- wontfix
categories:
- title: 🙌 Notable Changes
labels:
- category/notable
- title: 💥 Breaking Changes
labels:
- category/breaking
- title: 📄 Documentation
labels:
- documentation
- category/documentation
- title: 🏠 Internal
labels:
- internal
- title: 📦 Dependencies
labels:
- dependencies
- title: 🌈 Accessibility Improvements
labels:
- accessibility
- category/accessibility
- title: 🚀 New Features
labels:
- type/feature
- category/feature
- type/enhancement
- category/enhancement
- title: 🐛 Bug Fixes
labels:
- '*'
-56
View File
@@ -1,56 +0,0 @@
name: Backoffice Static Web Apps CI/CD
on:
push:
branches:
- main
- v*/dev
paths:
- src/Umbraco.Web.UI.Client/package.json
- src/Umbraco.Web.UI.Client/package-lock.json
- src/Umbraco.Web.UI.Client/src/**
- .github/workflows/azure-backoffice.yml
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- main
- v*/dev
workflow_dispatch:
jobs:
build_and_deploy_job:
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed' && contains(github.event.pull_request.labels.*.name, 'preview/backoffice') && github.repository == github.event.pull_request.head.repo.full_name)
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v6
with:
submodules: true
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
production_branch: main
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_VICTORIOUS_GROUND_017B08103 }}
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
action: "upload"
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
app_location: "src/Umbraco.Web.UI.Client" # App source code path
app_build_command: "npm run build:for:static"
output_location: "dist" # Built app content directory - optional
skip_api_build: true # Set to true if you do not have an Azure Functions API in your repo
###### End of Repository/Build Configurations ######
close_pull_request_job:
if: github.event_name == 'pull_request' && github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'preview/backoffice') && github.repository == github.event.pull_request.head.repo.full_name
runs-on: ubuntu-latest
name: Close Pull Request Job
steps:
- name: Close Pull Request
id: closepullrequest
uses: Azure/static-web-apps-deploy@v1
with:
app_location: "src/Umbraco.Web.UI.Client"
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_VICTORIOUS_GROUND_017B08103 }}
action: "close"
-57
View File
@@ -1,57 +0,0 @@
name: Storybook CI/CD
on:
push:
branches:
- main
- v*/dev
paths:
- src/Umbraco.Web.UI.Client/package.json
- src/Umbraco.Web.UI.Client/package-lock.json
- src/Umbraco.Web.UI.Client/src/**
- .github/workflows/azure-storybook.yml
pull_request:
types: [opened, synchronize, reopened, closed]
branches:
- main
- v*/dev
workflow_dispatch:
env:
NODE_OPTIONS: --max_old_space_size=16384
jobs:
build_and_deploy_job:
if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed' && contains(github.event.pull_request.labels.*.name, 'preview/storybook') && github.repository == github.event.pull_request.head.repo.full_name)
runs-on: ubuntu-latest
name: Build and Deploy Job
steps:
- uses: actions/checkout@v6
- name: Build And Deploy
id: builddeploy
uses: Azure/static-web-apps-deploy@v1
with:
production_branch: main
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ORANGE_SEA_0C7411A03 }}
repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
action: "upload"
###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
# For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
app_location: "src/Umbraco.Web.UI.Client" # App source code path
app_build_command: "npm run storybook:build"
output_location: "/storybook-static" # Built app content directory - optional
skip_api_build: true # Set to true if you do not have an Azure Functions API in your repo
###### End of Repository/Build Configurations ######
close_pull_request_job:
if: github.event_name == 'pull_request' && github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'preview/storybook') && github.repository == github.event.pull_request.head.repo.full_name
runs-on: ubuntu-latest
name: Close Pull Request Job
steps:
- name: Close Pull Request
id: closepullrequest
uses: Azure/static-web-apps-deploy@v1
with:
app_location: "src/Umbraco.Web.UI.Client"
azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ORANGE_SEA_0C7411A03 }}
action: "close"
-88
View File
@@ -1,88 +0,0 @@
name: Claude PR Review
on:
pull_request:
types: [opened, ready_for_review, reopened]
# NOTE: `pull_request_target` would let this workflow review fork PRs
# (with access to secrets), but the action currently fails during OIDC
# token exchange with "401 Unauthorized - Invalid OIDC token" on that
# event. PR #579 added `pull_request_target` routing to the action, but
# Anthropic's `/github-app-token-exchange` endpoint appears not to
# accept the token claims produced by that event. Re-enable once the
# upstream issue is resolved.
# See: https://github.com/anthropics/claude-code-action/issues/347
# https://github.com/anthropics/claude-code-action/issues/621
# pull_request_target:
# types: [opened, ready_for_review]
permissions:
contents: read
pull-requests: write
id-token: write
actions: read
jobs:
review:
# Skip fork PRs: secrets are not exposed on `pull_request` events from
# forks, so the action would fail with a red check. Remove this clause
# once upstream fork support lands (tracked in
# https://github.com/anthropics/claude-code-action/issues/939) and we
# can re-enable the `pull_request_target` trigger above.
if: >-
github.event.pull_request.draft == false
&& github.event.pull_request.head.repo.full_name == github.repository
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY_03 }}
# Enable progress tracking
track_progress: true
# Debug (set to true to show full output in logs, false to hide it and only post comments on the PR)
show_full_output: false
additional_permissions: "actions: read"
claude_args: "--model claude-sonnet-4-6 --allowedTools 'Bash(gh:*),Bash(git:*)'"
prompt: |
You are reviewing pull request #${{ github.event.pull_request.number }}
in the Umbraco CMS repository.
Read and execute the review procedure defined in `.claude/skills/umb-review/SKILL.md`.
For each finding that references a specific file and line:
- Post an individual inline PR comment on that line.
- Format: **[Severity]** explanation, then suggestion.
For the overall summary (header, impact, verdict):
- Post ONE top-level PR comment.
Do NOT use sticky/updating comments — post new individual comments.
After reviewing, apply labels to the PR based on changed files:
- `area/frontend` — if files under `src/Umbraco.Web.UI.Client/` are changed
- `area/backend` — if .cs files outside the frontend client are changed
- `area/test` — if only test files are changed
- `category/api` — if Management API or Delivery API files are changed
- `category/breaking` — if breaking changes were detected in the review
- `category/localization` — if localization/language files are changed
- `category/test-automation` — if only test files are changed
- `category/refactor` — if the PR is pure refactoring with no new features
- `category/performance` — if performance-related changes are detected
- `category/ux` — if user-facing changes are detected
- `category/ui` — if changes to the UI layer are detected
Only apply labels you are confident about. Never remove existing labels.
Be friendly and constructive. This project values community contributions.
Frame feedback as suggestions where possible.
Reserve firm language for genuine Critical issues only.
Run fully autonomously. Do NOT ask questions.
Only review changed files. Do not flag pre-existing issues.
Do not suggest changes that would themselves introduce breaking changes.
-91
View File
@@ -1,91 +0,0 @@
name: Claude
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned, labeled]
pull_request_review:
types: [submitted]
permissions:
contents: read
pull-requests: write
issues: write
id-token: write
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
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 1
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY_03 }}
assignee_trigger: "claude"
label_trigger: "claude"
base_branch: "main"
additional_permissions: "actions: read"
claude_args: "--model claude-sonnet-4-6 --max-turns 50 --allowedTools 'Bash(gh:*),Bash(git:*),Bash(npm:*),Bash(dotnet:*)'"
prompt: |
You are an AI assistant for the Umbraco CMS repository, an open-source
.NET CMS that welcomes community contributions.
You were triggered on issue/PR #${{ github.event.issue.number || github.event.pull_request.number }}.
Read the user's message and do what they ask. The trigger phrase
`@claude` is stripped before you see the message, so common requests
will look like:
- `review` — Review PR #${{ github.event.issue.number || github.event.pull_request.number }}.
Use `gh pr diff ${{ github.event.issue.number || github.event.pull_request.number }}`
and `gh pr view ${{ github.event.issue.number || github.event.pull_request.number }}`
to read the changes. Do NOT use git diff or the umb-review skill.
Focus on bugs, breaking changes, and architectural concerns.
Post inline comments for specific issues and a brief summary.
- `help` or a general question — Answer based on the codebase.
Read CLAUDE.md files for project structure and conventions.
- `fix ...` — Implement the requested fix on a new branch.
- `label` — Apply appropriate labels to the PR or issue.
If the message is empty or just whitespace, treat it as `review`
when on a PR, or `help` when on an issue.
If none of these match, read the user's message carefully and respond
to what they actually asked for.
## Labeling
When labeling PRs (based on changed files):
- `area/frontend`, `area/backend`, `area/test`
- `category/api`, `category/breaking`, `category/localization`
- `category/refactor`, `category/performance`, `category/ux`, `category/ui`
- `category/test-automation`
When labeling issues (based on content):
- `area/frontend`, `area/backend`, `area/test`
- `affected/v14` through `affected/v17`, `affected/backoffice`
- `category/api`, `category/localization`, `category/performance`
- `category/ux`, `category/ui`
Only apply labels you are confident about. Never remove existing labels.
## Tone
Be friendly and constructive. Frame feedback as suggestions.
Reserve firm language for genuine critical issues only.
## Constraints
- Run fully autonomously. Do NOT ask questions.
- Do not suggest changes that would introduce breaking changes.
+52 -55
View File
@@ -2,70 +2,67 @@ name: "Code scanning - action"
on:
push:
branches:
- "*/dev"
- "*/main"
- "main"
- "release/*"
branches: [v8/contrib,v8/dev,v8/bug,v8/feature]
pull_request:
# The branches below must be a subset of the branches above
branches:
- "*/dev"
- "*/main"
- "main"
- "release/*"
schedule:
- cron: "33 2 * * 1"
permissions:
contents: read
env:
dotnetVersion: 9.x
dotnetIncludePreviewVersions: "preview"
solution: umbraco.sln
buildConfiguration: SkipTests
DOTNET_NOLOGO: true
DOTNET_GENERATE_ASPNET_CERTIFICATE: false
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
NODE_OPTIONS: --max_old_space_size=16384
- cron: '0 7 * * 2'
jobs:
CodeQL-Build:
name: Analyze (${{ matrix.language }})
permissions:
actions: read # for github/codeql-action/init to get workflow details
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/analyze to upload SARIF results
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- language: csharp
build-mode: none
- language: javascript-typescript
build-mode: none
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# We use the setup-dotnet action to set up .NET Core, otherwise the CodeQL CLI will not work with preview versions.
- name: Setup .NET from global.json
uses: actions/setup-dotnet@v4
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
config-file: ./.github/config/codeql-config.yml
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
- name: configure Pagefile
uses: al-cheb/configure-pagefile-action@v1.2
with:
minimum-size: 8GB
maximum-size: 32GB
- run: |
echo "Run Umbraco-CMS build"
pwsh -command .\build\build.ps1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
with:
config-file: ./.github/config/codeql-config.yml
# This job is to prevent the workflow status from showing as failed when all other jobs are skipped - See https://github.community/t/workflow-is-failing-if-no-job-can-be-ran-due-to-condition/16873
always_job:
name: Always run job
runs-on: ubuntu-latest
steps:
- name: Always run
run: echo "This job is to prevent the workflow status from showing as failed when all other jobs are skipped"
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
-84
View File
@@ -1,84 +0,0 @@
name: Issue Deduplication
on:
issues:
types: [ opened ]
workflow_dispatch:
inputs:
issue_number:
description: 'Issue number to analyze for duplicates'
required: true
type: number
jobs:
deduplicate:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
issues: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 1
- name: Check for duplicate issues
uses: anthropics/claude-code-action@v1
with:
prompt: |
Analyze this new issue and check if it's a duplicate of existing issues in the repository.
Issue: #${{ github.event.issue.number || inputs.issue_number }}
Repository: ${{ github.repository }}
Your task:
1. Use mcp__github__get_issue to get details of the current issue (#${{ github.event.issue.number || inputs.issue_number }})
2. Search for similar existing issues using mcp__github__search_issues with relevant keywords from the issue title and body
3. Compare the new issue with existing ones to identify potential duplicates
Criteria for duplicates:
- Same bug or error being reported
- Same feature request (even if worded differently)
- Same question being asked
- Issues describing the same root problem
If you find duplicates:
- Add a comment on the new issue linking to the original issue(s)
- Apply the "duplicate" and "state/needs-investigation" labels to the new issue
- Be polite and explain why it's a duplicate
- Suggest the user follow the original issue for updates
If it's NOT a duplicate:
- Don't add any comments
- You may apply appropriate topic labels based on the issue content
Use these tools:
- mcp__github__get_issue: Get issue details
- mcp__github__search_issues: Search for similar issues
- mcp__github__list_issues: List recent issues if needed
- mcp__github__add_issue_comment: Add a comment if duplicate found
- mcp__github__update_issue: Add labels
Be thorough but efficient. Focus on finding true duplicates, not just similar issues.
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY_03 }}
# Issues are opened by community members without write access, so the
# default OIDC token exchange fails with "User does not have write
# access on this repository". Pass `github_token` explicitly and set
# `allowed_non_write_users` to bypass that check. Safe here because
# `permissions:` and `--allowedTools` below are tightly scoped to
# issue operations only.
github_token: ${{ secrets.GITHUB_TOKEN }}
allowed_non_write_users: "*"
# Surface full SDK output (including tool calls and permission denials)
# to diagnose why Claude sometimes only partially completes (e.g. labels
# an issue but skips the comment). Safe to leave on — no secrets in output.
show_full_output: true
claude_args: |
--model claude-haiku-4-5 --allowedTools "mcp__github__get_issue,mcp__github__search_issues,mcp__github__list_issues,mcp__github__add_issue_comment,mcp__github__update_issue,mcp__github__get_issue_comments"
@@ -1,51 +0,0 @@
name: issue-first-response
on:
issues:
types: [opened]
jobs:
send-response:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Install dependencies
run: |
npm install node-fetch@2
- name: Fetch random comment 🗣️ and add it to the issue
uses: actions/github-script@v6
with:
script: |
const response = await fetch('https://collaboratorsv2.euwest01.umbraco.io/umbraco/api/comments/PostComment', {
method: 'post',
body: JSON.stringify({
repo: '${{ github.repository }}',
number: '${{ github.event.number }}',
actor: '${{ github.actor }}',
commentType: 'opened-issue-first-comment'
}),
headers: {
'Authorization': 'Bearer ${{ secrets.OUR_BOT_API_TOKEN }}',
'Content-Type': 'application/json'
}
});
try {
const data = await response.text();
if(response.status === 200 && data !== '') {
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: data
});
} else {
console.log("Status code did not indicate success:", response.status);
console.log("Returned data:", data);
}
} catch(error) {
console.log(error);
}
@@ -1,164 +0,0 @@
name: Create a release discussions for each new version label
on:
schedule:
- cron: "0 * * * *" # every hour
workflow_dispatch: # allow manual runs
permissions:
contents: read
discussions: write
issues: read
pull-requests: read
jobs:
reconcile:
if: github.repository == 'umbraco/Umbraco-CMS'
runs-on: ubuntu-latest
steps:
- name: Reconcile release/* labels → discussions
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const categoryName = "Releases";
// 24h cutoff
const since = new Date(Date.now() - 24*60*60*1000).toISOString();
core.info(`Scanning issues/PRs updated since ${since}`);
// fetch repo + discussion categories
const repoData = await github.graphql(`
query($owner:String!, $repo:String!){
repository(owner:$owner, name:$repo){
id
discussionCategories(first:100){ nodes { id name } }
}
}
`, { owner, repo });
const repoId = repoData.repository.id;
const category = repoData.repository.discussionCategories.nodes.find(c => c.name === categoryName);
if (!category) {
core.setFailed(`Discussion category "${categoryName}" not found`);
return;
}
const categoryId = category.id;
// paginate issues/PRs updated in last 24h
for await (const { data: items } of github.paginate.iterator(
github.rest.issues.listForRepo,
{ owner, repo, state: "all", since, per_page: 100 }
)) {
for (const item of items) {
const releaseLabels = (item.labels || [])
.map(l => (typeof l === "string" ? l : l.name)) // always get the name
.filter(n => typeof n === "string" && n.startsWith("release/") && n !== "release/no-notes");
if (releaseLabels.length === 0) continue;
core.info(`#${item.number}: ${releaseLabels.join(", ")}`);
for (const labelName of releaseLabels) {
const version = labelName.substring("release/".length);
const titleTarget = `Release: ${version}`;
// search discussions
let discussionId = null;
let cursor = null;
while (true) {
const page = await github.graphql(`
query($owner:String!, $repo:String!, $cursor:String){
repository(owner:$owner, name:$repo){
discussions(first:50, after:$cursor){
nodes{
id
title
url
category{ name }
labels(first:50){ nodes{ name } }
}
pageInfo{ hasNextPage endCursor }
}
}
}
`, { owner, repo, cursor });
const nodes = page.repository.discussions.nodes;
const byLabel = nodes.find(d =>
d.category?.name === categoryName &&
d.labels?.nodes?.some(l => l.name === labelName)
);
if (byLabel) { discussionId = byLabel.id; break; }
const byTitle = nodes.find(d =>
d.category?.name === categoryName &&
d.title === titleTarget
);
if (byTitle) { discussionId = byTitle.id; break; }
if (!page.repository.discussions.pageInfo.hasNextPage) break;
cursor = page.repository.discussions.pageInfo.endCursor;
}
if (!discussionId) {
core.info(`→ Creating discussion for ${labelName}`);
const body =
`**Release date:** TODO (YYYY-MM-DD)\n\n` +
`### Links\n` +
`- [Issues and pull requests marked for version ${version}](https://github.com/${owner}/${repo}/issues?q=label%3A${encodeURIComponent(labelName)})\n`;
const created = await github.graphql(`
mutation($repoId:ID!, $catId:ID!, $title:String!, $body:String!){
createDiscussion(input:{
repositoryId:$repoId,
categoryId:$catId,
title:$title,
body:$body
}){ discussion{ id url } }
}
`, { repoId, catId: categoryId, title: titleTarget, body });
discussionId = created.createDiscussion.discussion.id;
// lock the discussion to prevent replies
await github.graphql(`
mutation($id:ID!){
lockLockable(input:{ lockableId:$id }) {
clientMutationId
}
}
`, { id: discussionId });
core.info(`🔒 Locked discussion ${discussionId}`);
} else {
core.info(`→ Found existing discussion for ${labelName}`);
}
// ensure label exists
let labelId;
try {
await github.rest.issues.getLabel({ owner, repo, name: labelName });
} catch (e) {
if (e.status === 404) {
await github.rest.issues.createLabel({
owner, repo, name: labelName, color: "0E8A16"
});
} else { throw e; }
}
const labelNode = await github.graphql(`
query($owner:String!, $repo:String!, $name:String!){
repository(owner:$owner, name:$repo){ label(name:$name){ id } }
}
`, { owner, repo, name: labelName });
labelId = labelNode.repository.label?.id;
if (!labelId) continue;
// add label to discussion
await github.graphql(`
mutation($id:ID!, $labels:[ID!]!){
addLabelsToLabelable(input:{ labelableId:$id, labelIds:$labels }) {
clientMutationId
}
}
`, { id: discussionId, labels: [labelId] });
core.info(`✓ ${labelName} attached to discussion`);
}
}
}
-57
View File
@@ -1,57 +0,0 @@
name: pr-first-response
on:
pull_request_target:
types: [opened]
jobs:
send-response:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Fetch random comment 🗣️ and add it to the PR
uses: actions/github-script@v6
with:
script: |
const response = await fetch('https://collaboratorsv2.euwest01.umbraco.io/umbraco/api/comments/PostComment', {
method: 'post',
body: JSON.stringify({
repo: '${{ github.repository }}',
number: '${{ github.event.number }}',
actor: '${{ github.actor }}',
commentType: 'opened-pr-first-comment'
}),
headers: {
'Authorization': 'Bearer ${{ secrets.OUR_BOT_API_TOKEN }}',
'Content-Type': 'application/json'
}
});
try {
const data = await response.text();
if(response.status === 200 && data !== '') {
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: data
});
} else {
console.log("Returned data not indicate success.");
if(response.status !== 200) {
console.log("Status code:", response.status)
}
console.log("Returned data:", data);
if(data === '') {
console.log("An empty response usually indicates that either no comment was found or the actor user was not eligible for getting an automated response (HQ users are not getting auto-responses).")
}
}
} catch(error) {
console.log(error);
}
-99
View File
@@ -1,99 +0,0 @@
name: "SonarQube Cloud - Analysis"
# This workflow runs the full SonarCloud analysis with the SONAR_TOKEN secret.
# It is skipped for fork PRs since secrets are not available in that context.
on:
push:
branches:
- main
- "v*/dev"
- "v*/main"
- "release/*"
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
permissions:
contents: read
env:
SONAR_PROJECT_KEY: umbraco_Umbraco-CMS
SONAR_ORGANIZATION: umbraco
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
analyze:
name: Build and analyze
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork != true
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup .NET from global.json
uses: actions/setup-dotnet@v5
- name: Setup Java 21
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: "21"
- name: Cache SonarQube packages
uses: actions/cache@v5
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Install tools
run: |
dotnet tool install --global dotnet-sonarscanner
dotnet tool install --global dotnet-coverage
- name: Load sonar params
run: echo "SONARQUBE_SCANNER_PARAMS=$(jq -c . .github/workflows/sonarcloud/sonar-params.json)" >> $GITHUB_ENV
- name: Begin analysis
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
dotnet-sonarscanner begin \
/k:"$SONAR_PROJECT_KEY" \
/o:"$SONAR_ORGANIZATION" \
/d:sonar.token="$SONAR_TOKEN" \
/d:sonar.scanner.skipJreProvisioning=true
- name: Restore
run: dotnet restore umbraco.sln
- name: Build solution
run: GITHUB_ENV=/dev/null dotnet build umbraco.sln --no-restore -clp:ErrorsOnly # prevent sonar MSBuild integration from writing malformed values to $GITHUB_ENV
- name: Run unit tests with coverage
id: tests
continue-on-error: true
run: |
dotnet-coverage collect \
"dotnet test tests/Umbraco.Tests.UnitTests/Umbraco.Tests.UnitTests.csproj --no-build" \
--output TestResults/coverage.xml \
--output-format xml
- name: Warn on test failure
if: steps.tests.outcome == 'failure'
run: |
if [ -f TestResults/coverage.xml ]; then
echo "::warning::Unit tests failed - SonarCloud analysis will proceed with the collected coverage data"
else
echo "::warning::Unit tests failed and no coverage data was collected"
fi
- name: End analysis
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: dotnet-sonarscanner end /d:sonar.token="$SONAR_TOKEN"
@@ -1,7 +0,0 @@
{
"sonar.cs.vscoveragexml.reportsPaths": "TestResults/coverage.xml",
"sonar.inclusions": "src/**,templates/**,tools/**,tests/**,.github/**,build/**",
"sonar.exclusions": "**/bin/**,**/obj/**,**/node_modules/**,**/lang/*.ts,**/mocks/**,**/wwwroot/**,**/dist-cms/**,**/*.generated.cs,src/Umbraco.Web.UI/umbraco/**,src/Umbraco.Cms.Persistence.EFCore.*/Migrations/**,src/Umbraco.Web.UI.Client/src/packages/core/backend-api/**,**/.nuget/**",
"sonar.test.inclusions": "tests/**,**/*.test.ts,**/*.spec.ts",
"sonar.typescript.tsconfigPaths": "src/Umbraco.Web.UI.Client/tsconfig.json,src/Umbraco.Web.UI.Client/tsconfig.node.json,src/Umbraco.Web.UI.Login/tsconfig.json"
}
-69
View File
@@ -1,69 +0,0 @@
name: Test Backoffice
on:
push:
branches:
- main
- release/*
- v*/dev
- v*/main
paths:
- src/Umbraco.Web.UI.Client/**
pull_request:
branches:
- main
- release/*
- v*/dev
- v*/main
paths:
- src/Umbraco.Web.UI.Client/**
# Allows GitHub to use this workflow to validate the merge queue
merge_group:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
env:
NODE_OPTIONS: --max_old_space_size=16384
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: src/Umbraco.Web.UI.Client
steps:
- uses: actions/checkout@v6
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version-file: src/Umbraco.Web.UI.Client/.nvmrc
cache: npm
cache-dependency-path: ./src/Umbraco.Web.UI.Client/package-lock.json
- run: npm ci --no-audit --no-fund --prefer-offline
- name: Check for circular dependencies
run: node devops/circular/index.js src
- run: npm run lint:errors
- run: npm run generate:tsconfig
- run: npm run generate:icons
- run: npm run build:for:cms
- run: npm run check:paths
- run: npm run generate:jsonschema:dist
test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: src/Umbraco.Web.UI.Client
steps:
- uses: actions/checkout@v6
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version-file: src/Umbraco.Web.UI.Client/.nvmrc
cache: npm
cache-dependency-path: ./src/Umbraco.Web.UI.Client/package-lock.json
- run: npm ci --no-audit --no-fund --prefer-offline
- run: npx playwright install --with-deps
- run: npm test
@@ -1,62 +0,0 @@
name: labeled-up-for-grabs-first-comment
on:
issues:
types:
- labeled
jobs:
send-response:
if: github.event.label.name == 'community/up-for-grabs'
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- name: Install dependencies
run: |
npm install node-fetch@2
- name: Fetch comment 🗣️ and add it to the issue
uses: actions/github-script@v6
with:
script: |
const response = await fetch('https://collaboratorsv2.euwest01.umbraco.io/umbraco/api/comments/PostComment', {
method: 'post',
body: JSON.stringify({
repo: '${{ github.repository }}',
number: '${{ github.event.issue.number }}',
actor: '${{ github.event.issue.user.login }}',
commentType: 'labeled-up-for-grabs-first-comment'
}),
headers: {
'Authorization': 'Bearer ${{ secrets.OUR_BOT_API_TOKEN }}',
'Content-Type': 'application/json'
}
});
try {
const data = await response.text();
if(response.status === 200 && data !== '') {
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: data
});
} else {
console.log("Returned data not indicate success.");
if(response.status !== 200) {
console.log("Status code:", response.status)
}
console.log("Returned data:", data);
if(data === '') {
console.log("An empty response usually indicates that either no comment was found or the actor user was not eligible for getting an automated response (HQ users are not getting auto-responses).")
}
}
} catch(error) {
console.log(error);
};
+180 -126
View File
@@ -1,126 +1,180 @@
#
# Umbraco CMS .gitignore
#
# Common files
*.obj
*.pdb
*.user
*.aps
*.pch
*.vspscc
*.orig
*.suo
*.vs10x
*.ndproj
*.ignorer.*
# Common directories
.DS_Store
._.DS_Store
.vs/
.idea/
# Build directories
[Bb]in/
[Oo]bj/
[Db]ebug/
[Rr]elease/
# Tools
_ReSharper*/
_NCrunch_*/
*.ncrunchsolution
*.ncrunchsolution.user
*.ncrunchproject
*.crunchsolution.cache
tools/NDepend/
[Tt]est[Rr]esult*
[Bb]uild[Ll]og.*
[Ss]ource
[Ss]andbox
node_modules
lib-bower
*.psess
*.vspx
NDependOut/
QueryResult.htm
tools/docfx/
# csharp-docs
/build/csharp-docs/api/
/build/csharp-docs/_site/
# Local config
.claude/*
!.claude/skills/
!.claude/settings.json
.env.local
# Build
/build.out/
/build.tmp/
/build/hooks/
/build/temp/
# Build output
/build/docs.zip
/build/ui-docs.zip
/build/csharp-docs.zip
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/auth
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/backoffice
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/assets
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/js
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/lib
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/views/*
!/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/views/errors
/src/Umbraco.Cms.StaticAssets/wwwroot/umbraco/login
# Environment specific data
/src/Umbraco.Web.UI/wwwroot/[Mm]edia/
/src/Umbraco.Web.UI/App_Code/
/src/Umbraco.Web.UI/App_Plugins/
/src/Umbraco.Web.UI/[Uu]mbraco/[Dd]ata/
/src/Umbraco.Web.UI/[Uu]mbraco/[Ll]ogs/
/src/Umbraco.Web.UI/[Uu]mbraco/[Mm]odels/
/src/Umbraco.Web.UI/Views/
!/src/Umbraco.Web.UI/Views/Partials/blocklist/
!/src/Umbraco.Web.UI/Views/Partials/grid/
!/src/Umbraco.Web.UI/Views/_ViewImports.cshtml
/src/Umbraco.Web.UI/appsettings.json
/src/Umbraco.Web.UI/appsettings.Development.json
/src/Umbraco.Web.UI/appsettings.Local.json
# Tests
/tests/Umbraco.Tests.AcceptanceTest/.env
/tests/Umbraco.Tests.AcceptanceTest/playwright/.auth
/tests/Umbraco.Tests.Integration.SqlCe/DatabaseContextTests.sdf
/tests/Umbraco.Tests.Integration.SqlCe/[Uu]mbraco/[Dd]ata/TEMP/
/tests/Umbraco.Tests.Integration/appsettings.Tests.Local.json
/tests/Umbraco.Tests.Integration/TEMP/
/tests/Umbraco.Tests.Integration/[Uu]mbraco/[Dd]ata/
/tests/Umbraco.Tests.Integration/[Uu]mbraco/[Ll]ogs/
/tests/Umbraco.Tests.Integration/Views/
/tests/Umbraco.Tests.UnitTests/[Uu]mbraco/[Dd]ata/TEMP/
/BenchmarkDotNet.Artifacts/
playwright-report
trace.zip
/tests/Umbraco.Tests.AcceptanceTest/results
/tests/Umbraco.Tests.AcceptanceTest/dist
# Ignore auto-generated schema
/src/Umbraco.Cms.Targets/tasks/
/src/Umbraco.Cms.Targets/appsettings-schema.*.json
/src/Umbraco.Cms.Targets/umbraco-package-schema.json
/src/Umbraco.Web.UI/appsettings-schema.json
/src/Umbraco.Web.UI/appsettings-schema.*.json
/src/Umbraco.Web.UI/umbraco-package-schema.json
/src/Umbraco.Web.UI.Client/umbraco-package-schema.json
/tests/Umbraco.Tests.Integration/appsettings-schema.json
/tests/Umbraco.Tests.Integration/appsettings-schema.*.json
/tests/Umbraco.Tests.Integration/umbraco-package-schema.json
/src/Umbraco.Cms/appsettings-schema.json
.playwright-mcp/
# SonarQube local analysis cache
.sonarqube/
#
# Umbraco Cms Git Ignore
#
# common files
*.obj
*.pdb
*.user
*.aps
*.pch
*.vspscc
*.orig
*.suo
*.vs10x
*.ndproj
*.ignorer.*
# common directories
.DS_Store
._.DS_Store
.vs/
/local/
# build directories
[Bb]in/
[Db]ebug*/
[Rr]elease*/
obj/
# tools
_ReSharper*/
_NCrunch_*/
*.ncrunchsolution
*.ncrunchsolution.user
*.ncrunchproject
*.crunchsolution.cache
tools/NDepend/
[Tt]est[Rr]esult*
[Bb]uild[Ll]og.*
*.[Pp]ublish.xml
[sS]ource
[sS]andbox
umbraco.config
App_Data/TEMP/*
[Uu]mbraco/[Pp]resentation/[Uu]mbraco/[Pp]lugins/*
[Uu]mbraco/[Pp]resentation/[Uu]ser[Cc]ontrols/*
[Uu]mbraco/[Pp]resentation/[Ss]cripts/*
[Uu]mbraco/[Pp]resentation/[Ff]onts/*
[Uu]mbraco/[Pp]resentation/[Cc]ss/*
src/Umbraco.Web.UI/[Cc]ss/*
src/Umbraco.Web.UI/App_Code/*
src/Umbraco.Web.UI/App_Data/*
src/Umbraco.Web.UI/data/*
src/Umbraco.Tests/App_Data/*
src/Umbraco.Web.UI/[Mm]edia/*
src/Umbraco.Web.UI/[Mm]aster[Pp]ages/*
src/Umbraco.Web.UI/[Mm]acro[Ss]cripts/*
!src/Umbraco.Web.UI/[Mm]acro[Ss]cripts/[Ww]eb.[Cc]onfig
src/Umbraco.Web.UI/[Xx]slt/*
src/Umbraco.Web.UI/[Ii]mages/*
src/Umbraco.Web.UI/[Ss]cripts/*
src/Umbraco.Web.UI/Web.*.config.transformed
umbraco/presentation/umbraco/plugins/uComponents/uComponentsInstaller.ascx
umbraco/presentation/packages/uComponents/MultiNodePicker/CustomTreeService.asmx
src/Umbraco.Tests/config/applications.config
src/Umbraco.Tests/config/trees.config
src/Umbraco.Web.UI/web.config
src/Umbraco.Web.UI/[Cc]onfig/ClientDependency.config
src/Umbraco.Web.UI/[Cc]onfig/serilog.config
src/Umbraco.Web.UI/[Cc]onfig/serilog.user.config
src/Umbraco.Tests/config/404handlers.config
src/Umbraco.Web.UI/[Vv]iews/*.cshtml
src/Umbraco.Web.UI/[Vv]iews/*.vbhtml
src/Umbraco.Tests/[Cc]onfig/umbracoSettings.config
src/Umbraco.Web.UI/[Vv]iews/*
src/packages/
src/packages/repositories.config
src/Umbraco.Web.UI/[Ww]eb.config
*.transformed
node_modules
lib-bower
src/Umbraco.Web.UI/[Uu]mbraco/[Ll]ib/*
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/umbraco.*
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/*.loader.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/init.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/routes.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.dev.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.dev.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/canvasdesigner.*.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/navigation.controller.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.controller.js
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/utilities.js
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.css
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.html
src/Umbraco.Web.UI/[Uu]mbraco/[Aa]ssets/*
src/Umbraco.Web.UI.Client/[Bb]uild/*
src/Umbraco.Web.UI.Client/[Bb]uild/[Bb]elle/
src/Umbraco.Web.UI/[Uu]ser[Cc]ontrols/
src/Umbraco.Web.UI.Client/src/[Ll]ess/*.css
src/Umbraco.Web.UI.Client/vwd.webinfo
src/Umbraco.Web.UI/App_Plugins/*
src/*.psess
src/*.vspx
NDependOut/*
QueryResult.htm
src/Umbraco.Web.UI/[Cc]onfig/appSettings.config
src/Umbraco.Web.UI/[Cc]onfig/connectionStrings.config
src/Umbraco.Web.UI/[Uu]mbraco/plugins/*
build/ApiDocs/*
build/ApiDocs/Output/*
src/Umbraco.Web.UI.Client/bower_components/*
/src/Umbraco.Web.UI/[Uu]mbraco/preview
/src/Umbraco.Web.UI/[Uu]mbraco/preview.old
# ignore rule for clearing out Belle (avoid rebuilding all the time)
preserve.belle
#Ignore Rule for output of generated documentation files from Grunt docserve
src/Umbraco.Web.UI.Docs/api
src/Umbraco.Web.UI.Docs/package-lock.json
src/*.boltdata/
src/umbraco.sln.ide/*
src/.vs/
src/Umbraco.Web.UI/[Jj]s/*
src/Umbraco.Tests/[Mm]edia
tools/docfx/*
apidocs/_site/*
src/*/project.lock.json
src/.idea/*
apidocs/api/*
build/docs.zip
build/ui-docs.zip
build/csharp-docs.zip
src/packages/
src/PrecompiledWeb/*
# build
build.out/
build.tmp/
build/hooks/
build/temp/
# eof
/src/Umbraco.Web.UI.Client/TESTS-*.xml
/src/ApiDocs/api/*
/src/Umbraco.Web.UI.Client/package-lock.json
# Acceptance tests
cypress.env.json
/src/Umbraco.Tests.AcceptanceTest/cypress/support/chainable.ts
/src/Umbraco.Tests.AcceptanceTest/package-lock.json
/src/Umbraco.Tests.AcceptanceTest/cypress/videos/
/src/Umbraco.Tests.AcceptanceTest/cypress/screenshots/
src/Umbraco.Web.UI/Umbraco/telemetrics-id.umb
/src/Umbraco.Web.UI/config/umbracoSettings.config
-82
View File
@@ -1,82 +0,0 @@
is_global = true
##########################################
# StyleCopAnalyzers Settings
##########################################
# All constant fields must be PascalCase
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1303.md
dotnet_naming_symbols.stylecop_constant_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private
dotnet_naming_symbols.stylecop_constant_fields_group.required_modifiers = const
dotnet_naming_symbols.stylecop_constant_fields_group.applicable_kinds = field
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.symbols = stylecop_constant_fields_group
dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.style = pascal_case_style
# All static readonly fields must be PascalCase
# Ajusted to ignore private fields.
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1311.md
dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected
dotnet_naming_symbols.stylecop_static_readonly_fields_group.required_modifiers = static, readonly
dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_kinds = field
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.symbols = stylecop_static_readonly_fields_group
dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style
# No non-private instance fields are allowed
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md
dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected
dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group
dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style
# Local variables must be camelCase
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md
dotnet_naming_symbols.stylecop_local_fields_group.applicable_accessibilities = local
dotnet_naming_symbols.stylecop_local_fields_group.applicable_kinds = local
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.symbols = stylecop_local_fields_group
dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.style = camel_case_style
##########################################
# StyleCopAnalyzers rule severity
# https://github.com/DotNetAnalyzers/StyleCopAnalyzers
##########################################
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = suggestion
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.ReadabilityRules.severity = suggestion
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.NamingRules.severity = suggestion
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.SpacingRules.severity = suggestion
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.OrderingRules.severity = suggestion
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.MaintainabilityRules.severity = suggestion
dotnet_analyzer_diagnostic.category-StyleCop.CSharp.LayoutRules.severity = suggestion
dotnet_diagnostic.SA1101.severity = none # PrefixLocalCallsWithThis - stylecop appears to be ignoring dotnet_style_qualification_for_*
dotnet_diagnostic.SA1309.severity = none # FieldNamesMustNotBeginWithUnderscore
dotnet_diagnostic.SA1503.severity = warning # BracesMustNotBeOmitted
dotnet_diagnostic.SA1117.severity = warning # ParametersMustBeOnSameLineOrSeparateLines
dotnet_diagnostic.SA1116.severity = warning # SplitParametersMustStartOnLineAfterDeclaration
dotnet_diagnostic.SA1122.severity = warning # UseStringEmptyForEmptyStrings
dotnet_diagnostic.SA1028.severity = warning # CodeMustNotContainTrailingWhitespace
dotnet_diagnostic.SA1500.severity = warning # BracesForMultiLineStatementsMustNotShareLine
dotnet_diagnostic.SA1401.severity = warning # FieldsMustBePrivate
dotnet_diagnostic.SA1519.severity = warning # BracesMustNotBeOmittedFromMultiLineChildStatement
dotnet_diagnostic.SA1111.severity = warning # ClosingParenthesisMustBeOnLineOfLastParameter
dotnet_diagnostic.SA1520.severity = warning # UseBracesConsistently
dotnet_diagnostic.SA1407.severity = warning # ArithmeticExpressionsMustDeclarePrecedence
dotnet_diagnostic.SA1400.severity = warning # AccessModifierMustBeDeclared
dotnet_diagnostic.SA1119.severity = warning # StatementMustNotUseUnnecessaryParenthesis
dotnet_diagnostic.SA1649.severity = warning # FileNameMustMatchTypeName
dotnet_diagnostic.SA1121.severity = warning # UseBuiltInTypeAlias
dotnet_diagnostic.SA1132.severity = warning # DoNotCombineFields
dotnet_diagnostic.SA1134.severity = warning # AttributesMustNotShareLine
dotnet_diagnostic.SA1106.severity = warning # CodeMustNotContainEmptyStatements
dotnet_diagnostic.SA1312.severity = warning # VariableNamesMustBeginWithLowerCaseLetter
dotnet_diagnostic.SA1310.severity = warning # FieldNamesMustNotContainUnderscore
dotnet_diagnostic.SA1303.severity = warning # ConstFieldNamesMustBeginWithUpperCaseLetter
dotnet_diagnostic.SA1130.severity = warning # UseLambdaSyntax
dotnet_diagnostic.SA1405.severity = warning # DebugAssertMustProvideMessageText
dotnet_diagnostic.SA1205.severity = warning # PartialElementsMustDeclareAccess
dotnet_diagnostic.SA1306.severity = warning # FieldNamesMustBeginWithLowerCaseLetter
dotnet_diagnostic.SA1209.severity = warning # UsingAliasDirectivesMustBePlacedAfterOtherUsingDirectives
dotnet_diagnostic.SA1216.severity = warning # UsingStaticDirectivesMustBePlacedAtTheCorrectLocation
dotnet_diagnostic.SA1133.severity = warning # DoNotCombineAttributes
dotnet_diagnostic.SA1135.severity = warning # UsingDirectivesMustBeQualified
-14
View File
@@ -1,14 +0,0 @@
{
"mcpServers": {
"umbraco-cms": {
"command": "npx",
"args": ["@umbraco-cms/mcp-dev@17"]
},
"playwright": {
"command": "npx",
"args": [
"@playwright/mcp@latest"
]
}
}
}
-128
View File
@@ -1,128 +0,0 @@
{
"version": "0.2.0",
"compounds": [
{
"name": "Backoffice Launch (Vite + .NET Core)",
"configurations": [
"Backoffice Launch Vite (Chrome)",
".NET Core Serve with External Auth (web)"
],
"stopAll": true,
"presentation": {
"group": "1"
}
}
],
"configurations": [
{
"name": "Backoffice Launch Vite (Chrome)",
"request": "launch",
"env": {
"VITE_UMBRACO_USE_MSW": "${input:AskForMockServer}"
},
"runtimeExecutable": "npx",
"runtimeArgs": ["vite"],
"type": "node",
"cwd": "${workspaceFolder}/src/Umbraco.Web.UI.Client",
"skipFiles": ["<node_internals>/**", "node_modules/**"],
"smartStep": true,
"autoAttachChildProcesses": true,
"serverReadyAction": {
"killOnServerStop": true,
"action": "debugWithChrome",
"pattern": "Local: http://localhost:([0-9]+)",
"uriFormat": "http://localhost:%s",
"webRoot": "${workspaceFolder}/src/Umbraco.Web.UI.Client"
},
"presentation": {
"group": "2"
}
},
{
"name": "Backoffice Attach Vite (Chrome)",
"request": "launch",
"type": "chrome",
"smartStep": true,
"url": "http://localhost:5173/",
"skipFiles": ["<node_internals>/**", "node_modules/**"],
"webRoot": "${workspaceFolder}/src/Umbraco.Web.UI.Client",
"presentation": {
"group": "2"
}
},
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"program": "dotnet",
"args": ["run"],
"cwd": "${workspaceFolder}/src/Umbraco.Web.UI",
"stopAtEntry": false,
"requireExactSource": false,
"postDebugTask": "kill-umbraco-web-ui",
// Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\\\bNow listening on:\\\\s+(https?://\\\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Umbraco.Web.UI/Views"
},
"presentation": {
"group": "3"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}",
"presentation": {
"group": "3"
}
},
{
"name": ".NET Core Serve with External Auth (web)",
"type": "coreclr",
"request": "launch",
"program": "dotnet",
"args": ["run"],
"cwd": "${workspaceFolder}/src/Umbraco.Web.UI",
"stopAtEntry": false,
"requireExactSource": false,
"checkForDevCert": true,
"postDebugTask": "kill-umbraco-web-ui",
"env": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_URLS": "https://localhost:44339",
"UMBRACO__CMS__WEBROUTING__UMBRACOAPPLICATIONURL": "https://localhost:44339",
"UMBRACO__CMS__SECURITY__BACKOFFICEHOST": "http://localhost:5173",
"UMBRACO__CMS__SECURITY__AUTHORIZECALLBACKPATHNAME": "/oauth_complete",
"UMBRACO__CMS__SECURITY__AUTHORIZECALLBACKLOGOUTPATHNAME": "/logout",
"UMBRACO__CMS__SECURITY__AUTHORIZECALLBACKERRORPATHNAME": "/error",
"UMBRACO__CMS__SECURITY__KEEPUSERLOGGEDIN": "true",
"UMBRACO__CMS__SECURITY__BACKOFFICETOKENCOOKIE__SAMESITE": "None"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Umbraco.Web.UI/Views"
},
"presentation": {
"group": "3"
}
}
],
"inputs": [
{
"id": "AskForMockServer",
"type": "promptString",
"description": "Use Mock Service Worker (MSW) for Backoffice API calls (off requires a running server)?",
"default": "off"
}
]
}
-1
View File
@@ -1 +0,0 @@
../src/Umbraco.Web.UI.Client/.vscode/lit.code-snippets
-15
View File
@@ -1,15 +0,0 @@
{
"cSpell.words": [
"backoffice",
"pickable",
"Pickable",
"Umbraco",
"unprovide",
"Unproviding"
],
"eslint.useFlatConfig": true,
"eslint.workingDirectories": [
"./src/Umbraco.Web.UI.Client/",
"./src/Umbraco.Web.UI.Login/"
]
}
-87
View File
@@ -1,87 +0,0 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build",
"detail": "Builds the client and SLN",
"promptOnClose": true,
"group": "build",
"dependsOn": ["Client Build", "Dotnet build"],
"problemMatcher": []
},
{
"label": "Client Install",
"detail": "install npm for Umbraco.Web.UI.Client",
"promptOnClose": true,
"type": "npm",
"script": "install",
"path": "src/Umbraco.Web.UI.Client/",
"problemMatcher": []
},
{
"label": "Client Build",
"detail": "runs npm run build for Umbraco.Web.UI.Client",
"promptOnClose": true,
"group": "build",
"type": "npm",
"script": "build:for:cms",
"path": "src/Umbraco.Web.UI.Client/",
"problemMatcher": []
},
{
"label": "Client Watch",
"detail": "runs npm run dev for Umbraco.Web.UI.Client",
"promptOnClose": true,
"group": "build",
"type": "npm",
"script": "dev",
"path": "src/Umbraco.Web.UI.Client/",
"problemMatcher": []
},
{
"label": "Dotnet build",
"detail": "Dotnet build of SLN",
"promptOnClose": true,
"group": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/umbraco.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "Dotnet watch",
"detail": "Dotnet run and watch of Web.UI",
"promptOnClose": true,
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "kill-umbraco-web-ui",
"type": "shell",
"problemMatcher": [],
"osx": {
"command": "pkill -f Umbraco.Web.UI"
},
"linux": {
"command": "pkill -f Umbraco.Web.UI"
},
"windows": {
"command": "taskkill /IM Umbraco.Web.UI.exe /F"
}
}
]
}
-635
View File
@@ -1,635 +0,0 @@
# Umbraco CMS - Multi-Project Repository
Enterprise-grade CMS built on .NET 10.0. This repository contains 21 production projects organized in a layered architecture with clear separation of concerns.
**Repository**: https://github.com/umbraco/Umbraco-CMS
**License**: MIT
**Main Branch**: `main`
---
## 1. Overview
### What This Repository Contains
**21 Production Projects** organized in 3 main categories:
1. **Core Architecture** (Domain & Infrastructure)
- `Umbraco.Core` - Interface contracts, domain models, notifications
- `Umbraco.Infrastructure` - Service implementations, data access, caching
2. **Web & APIs** (Presentation Layer)
- `Umbraco.Web.UI` - Main ASP.NET Core web application
- `Umbraco.Web.Common` - Shared web functionality, controllers, middleware
- `Umbraco.Cms.Api.Management` - Backoffice Management API (REST)
- `Umbraco.Cms.Api.Delivery` - Content Delivery API (headless)
- `Umbraco.Cms.Api.Common` - Shared API infrastructure
3. **Specialized Features** (Pluggable Modules)
- Persistence: EF Core (modern), NPoco (legacy) for SQL Server & SQLite
- Caching: `PublishedCache.HybridCache` (in-memory + distributed)
- Search: `Examine.Lucene` (full-text search)
- Imaging: `Imaging.ImageSharp` v1 & v2 (image processing)
- Other: Static assets, targets, development tools
**6 Test Projects**:
- `Umbraco.Tests.Common` - Shared test utilities
- `Umbraco.Tests.UnitTests` - Unit tests
- `Umbraco.Tests.Integration` - Integration tests
- `Umbraco.Tests.Benchmarks` - Performance benchmarks
- `Umbraco.Tests.AcceptanceTest` - E2E tests
- `Umbraco.Tests.AcceptanceTest.UmbracoProject` - Test instance
### Key Technologies
- **.NET 10.0** - Target framework for all projects
- **ASP.NET Core** - Web framework
- **Entity Framework Core** - Modern ORM
- **OpenIddict** - OAuth 2.0/OpenID Connect authentication
- **Microsoft.AspNetCore.OpenApi** - OpenAPI document generation
- **Swashbuckle.AspNetCore.SwaggerUI** - Swagger UI for API documentation
- **Lucene.NET** - Full-text search via Examine
- **ImageSharp** - Image processing
---
## 2. Repository Structure
```
Umbraco-CMS/
├── src/ # 21 production projects
│ ├── Umbraco.Core/ # Domain contracts (interfaces only)
│ │ └── CLAUDE.md # ⭐ Core architecture guide
│ ├── Umbraco.Infrastructure/ # Service implementations
│ ├── Umbraco.Web.Common/ # Web utilities
│ ├── Umbraco.Web.UI/ # Main web application
│ ├── Umbraco.Cms.Api.Management/ # Management API
│ ├── Umbraco.Cms.Api.Delivery/ # Delivery API (headless)
│ ├── Umbraco.Cms.Api.Common/ # Shared API infrastructure
│ │ └── CLAUDE.md # ⭐ API patterns guide
│ ├── Umbraco.PublishedCache.HybridCache/ # Content caching
│ ├── Umbraco.Examine.Lucene/ # Search indexing
│ ├── Umbraco.Cms.Persistence.EFCore/ # EF Core data access
│ ├── Umbraco.Cms.Persistence.EFCore.Sqlite/
│ ├── Umbraco.Cms.Persistence.EFCore.SqlServer/
│ ├── Umbraco.Cms.Persistence.Sqlite/ # Legacy SQLite
│ ├── Umbraco.Cms.Persistence.SqlServer/ # Legacy SQL Server
│ ├── Umbraco.Cms.Imaging.ImageSharp/ # Image processing v1
│ ├── Umbraco.Cms.Imaging.ImageSharp2/ # Image processing v2
│ ├── Umbraco.Cms.StaticAssets/ # Embedded assets
│ ├── Umbraco.Cms.DevelopmentMode.Backoffice/
│ ├── Umbraco.Cms.Targets/ # NuGet targets
│ └── Umbraco.Cms/ # Meta-package
├── tests/ # 6 test projects
│ ├── Umbraco.Tests.Common/
│ ├── Umbraco.Tests.UnitTests/
│ ├── Umbraco.Tests.Integration/
│ ├── Umbraco.Tests.Benchmarks/
│ ├── Umbraco.Tests.AcceptanceTest/
│ └── Umbraco.Tests.AcceptanceTest.UmbracoProject/
├── templates/ # Project templates
│ └── Umbraco.Templates/
├── tools/ # Build tools
│ └── Umbraco.JsonSchema/
├── umbraco.sln # Main solution file
├── Directory.Build.props # Shared build configuration
├── Directory.Packages.props # Centralized package versions
├── .editorconfig # Code style
└── .globalconfig # Roslyn analyzers
```
### Architecture Layers
**Dependency Flow** (unidirectional, always flows inward):
```
Web.UI → Web.Common → Infrastructure → Core
Api.Management → Api.Common → Infrastructure → Core
Api.Delivery → Api.Common → Infrastructure → Core
```
**Key Principle**: Core has NO dependencies (pure contracts). Infrastructure implements Core. Web/APIs depend on Infrastructure.
### Project Dependencies
**Core Layer**:
- `Umbraco.Core` → No dependencies (only Microsoft.Extensions.*)
**Infrastructure Layer**:
- `Umbraco.Infrastructure``Umbraco.Core`
- `Umbraco.PublishedCache.*``Umbraco.Infrastructure`
- `Umbraco.Examine.Lucene``Umbraco.Infrastructure`
- `Umbraco.Cms.Persistence.*``Umbraco.Infrastructure`
**Web Layer**:
- `Umbraco.Web.Common``Umbraco.Infrastructure` + caching + search
- `Umbraco.Web.UI``Umbraco.Web.Common` + all features
**API Layer**:
- `Umbraco.Cms.Api.Common``Umbraco.Web.Common`
- `Umbraco.Cms.Api.Management``Umbraco.Cms.Api.Common`
- `Umbraco.Cms.Api.Delivery``Umbraco.Cms.Api.Common`
---
## 3. Teamwork & Collaboration
### Branching Strategy
- **Main branch**: `main` (protected)
- **Branch naming convention**: `v<version>/<type>/<description>`
**Format**: `v{major-version}/{type}/{kebab-case-description}`
**Version**: Read from `version.json` in the repository root. Use the major version number (e.g., `v17` for version 17.x.x).
**Types**:
| Type | Use Case |
|------|----------|
| `feature` | New feature being introduced to the product |
| `bugfix` | Fix to an existing issue with the product |
| `qa` | Adding or updating unit, integration, or end-to-end tests |
| `improvement` | Update to something that already exists but isn't broken (UI finessing, refactoring) |
| `task` | Update that doesn't directly impact product behavior (dependency updates, build pipeline) |
**Description**: A short, kebab-case description (a few words). This should be prefixed with the GitHub issue number if the update is related to resolving a tracked issue.
**Examples**:
```
v17/bugfix/12345-correct-display-of-pending-migrations
v17/feature/add-webhook-support
v17/improvement/optimize-content-cache
v17/qa/add-media-service-tests
v17/task/update-ef-core-dependency
```
See `.github/CONTRIBUTING.md` for full guidelines.
### Pull Request Process
- **PR Template**: `.github/pull_request_template.md`
- **Required CI Checks**:
- All tests pass
- Code formatting (dotnet format)
- No build warnings
- **Merge Strategy**: Squash and merge (via GitHub UI)
- **Reviews**: Required from code owners
#### PR Naming Convention
Use the format: `Area: Description (closes #IssueID)`
**Examples**:
| Area | Description | Issue |
|------|-------------|-------|
| Relations: | Move persistence of relations from repository into notification handlers | (closes #00000) |
| Management API: | Correct the population of the parent for sibling items when retrieved under a folder | |
| Docs: | Updated contributing guidelines to welcome contributions on bugfixes | |
**Area**: The feature or aspect affected (e.g., UFM, TipTap, Docs, Segmentation, Migrations). Helps readers quickly understand what is being changed.
**Description Best Practices**:
- Include the area of change (Relations, Management API, etc.)
- Describe the change and its impact
- Be specific, not vague (describe "a golden retriever" not just "a dog")
**Issue Linking**: Add `(closes #IssueID)` to the title for readability, AND include a closing keyword on its own line in the PR body (e.g., `Fixes #IssueID`) so GitHub actually auto-links and auto-closes the issue on merge. GitHub only parses closing keywords (`closes`, `fixes`, `resolves`) from the PR body or commit messages — the title suffix is cosmetic and does **not** trigger auto-close on its own.
### Commit Messages
Follow Conventional Commits format:
```
<type>(<scope>): <description>
Types: feat, fix, docs, style, refactor, test, chore
Scope: project name (core, web, api, etc.)
Examples:
feat(core): add IContentService.GetByIds method
fix(api): resolve null reference in schema handler
docs(web): update routing documentation
```
### Code Owners
Project ownership is distributed across teams. Check individual project directories for ownership.
---
## 4. Architecture Patterns
### Core Architectural Decisions
1. **Layered Architecture with Dependency Inversion**
- Core defines contracts (interfaces)
- Infrastructure implements contracts that need Infrastructure-owned machinery
- Web/APIs consume implementations via DI
**Where service implementations live**: Services whose dependencies are satisfiable from Core interfaces alone (repositories, scope, config, other Core services) live in `Umbraco.Core/Services/` — this covers the majority of domain services (`MemberService`, `ContentService`, `MediaService`, `ContentTypeService`, `EntityService`, `AuditService`, `ExternalMemberService`, etc.). Service implementations only live in `Umbraco.Infrastructure/Services/Implement/` when they genuinely need Infrastructure concerns — Examine indexes (`ContentSearchService`, `MediaSearchService`, `IndexedEntitySearchService`), log files (`LogViewerRepository`), packaging internals (`PackagingService`), webhook firing (`WebhookFiringService`), distributed-job coordination (`DistributedJobService`). When adding a new service, default to Core and only move to Infrastructure if a concrete dependency forces it.
2. **Interface-First Design**
- All services defined as interfaces in Core
- Enables testing, polymorphism, extensibility
3. **Notification Pattern** (not C# events)
- See `/src/Umbraco.Core/CLAUDE.md` → "2. Notification System (Event Handling)"
4. **Composer Pattern** (DI registration)
- See `/src/Umbraco.Core/CLAUDE.md` → "3. Composer Pattern (DI Registration)"
5. **Scoping Pattern** (Unit of Work)
- See `/src/Umbraco.Core/CLAUDE.md` → "5. Scoping Pattern (Unit of Work)"
6. **Attempt Pattern** (operation results)
- `Attempt<TResult, TStatus>` instead of exceptions
- Strongly-typed operation status enums
### Key Design Patterns Used
- **Repository Pattern** - Data access abstraction
- **Unit of Work** - Scoping for transactions
- **Builder Pattern** - `ProblemDetailsBuilder` for API errors
- **Strategy Pattern** - OpenAPI handlers (schema ID, operation ID)
- **Options Pattern** - All configuration via `IOptions<T>`
- **Factory Pattern** - Content type factories
- **Mediator Pattern** - Notification aggregator
---
## 5. Avoiding Breaking Changes
No binary breaking changes are allowed within a major version. Three patterns are used:
### 5.1 Obsolete Constructor + StaticServiceProvider
When a public class needs new dependencies, obsolete the existing constructor and add a new one. The old constructor delegates to the new one, resolving missing deps via `StaticServiceProvider`.
```csharp
[Obsolete("Please use the constructor with all parameters. Scheduled for removal in Umbraco 19.")]
public MyService(IDependencyA depA)
: this(
depA,
StaticServiceProvider.Instance.GetRequiredService<IDependencyB>())
{
}
public MyService(IDependencyA depA, IDependencyB depB)
{
_depA = depA;
_depB = depB;
}
```
**Examples**:
- `ContentCollectionPresentationFactory` - added `FlagProviderCollection`
- `CacheInstructionService` - added `ILastSyncedManager`, `IRepositoryCacheVersionService`
- `DocumentPresentationFactory` - added `FlagProviderCollection`
**Rules**:
- Old constructor marked `[Obsolete("... Scheduled for removal in Umbraco {current-major+2}.")]`
- Old constructor calls new constructor via `: this(...)`
- Uses `StaticServiceProvider.Instance.GetRequiredService<T>()` for new params only
- DI registration must use the NEW constructor (old is for external consumers only)
### 5.2 Obsolete Method + New Overload
When a public method signature needs to change, add the new method/overload and obsolete the old. The obsolete method should call the new one with suitable defaults.
```csharp
[Obsolete("Use the overload taking all parameters. Scheduled for removal in Umbraco 19.")]
public void DoThing(string name)
=> DoThing(name, extraParam: null);
public void DoThing(string name, string? extraParam)
{
// Real implementation here
}
```
**Rules**:
- Old method marked `[Obsolete]` with removal schedule
- DRY: old method calls new method, providing defaults for new parameters
- All internal callers must be updated to use the new method
- No callers should remain on the obsolete method within the codebase
### 5.3 Default Interface Implementation
When adding methods to a public interface, provide a default implementation so existing external implementations don't break.
```csharp
public interface IMyService
{
// Existing method
void ExistingMethod();
// New method with default implementation
void NewMethod(string param)
=> ExistingMethod(); // delegate to existing if possible
}
```
**Strategies for the default** (in order of preference):
1. **Use existing interface methods** to satisfy the contract (even if not optimal)
2. **Return a sensible default** like empty collection, null, etc.
3. **Throw `NotImplementedException`** if no reasonable default exists
**Example**: `IContentService.SaveBlueprint` - new overload with `IContent? createdFromContent` has a default impl that calls the old method (ignoring the new param).
**Example**: `IDocumentPresentationFactory.CreateCulturePublishScheduleModels` - full default implementation with logic, uses `StaticServiceProvider` for dependency resolution within the interface.
**Rules**:
- Add `// TODO (V{next-major}): Remove the default implementation when {obsolete method} is removed.` comment
- Default impl should be functionally correct even if not optimal
- If using `StaticServiceProvider` in a default impl, note this is temporary
### 5.4 General Rules
- **Removal policy**: Obsoleted members must remain for at least one full major version before removal. If obsoleted in version N, the earliest removal is version N+2. For example, something obsoleted in v17 is scheduled for removal in v19 (giving the whole of v18 as a deprecation period).
- All `[Obsolete]` attributes must include **"Scheduled for removal in Umbraco {current+2}"**
- Read `version.json` to determine the current major version
- Suppress `CS0618` warnings where obsolete members must call each other:
```csharp
#pragma warning disable CS0618 // Type or member is obsolete
=> OldMethod(param);
#pragma warning restore CS0618 // Type or member is obsolete
```
- Update ALL internal callers to use the new API - no internal code should use obsolete members
---
## 6. Project-Specific Notes
### Centralized Package Management
**NuGet package versions** are centralized in `Directory.Packages.props`. There are two `Directory.Packages.props` files in the source tree, with multi-level merging enabled so the test file inherits from the root:
| File | Scope |
|------|-------|
| `Directory.Packages.props` (root) | Production source code packages — referenced by all `src/**` projects |
| `tests/Directory.Packages.props` | Test-only packages (NUnit, Moq, Bogus, BenchmarkDotNet, etc.) — adds entries on top of the inherited root file |
When updating dependencies, decide which file the package belongs in:
- A package used only by test projects → `tests/Directory.Packages.props`
- A package used by any production project (or by both production and tests) → root `Directory.Packages.props`
```xml
<!-- Individual projects reference WITHOUT version -->
<PackageReference Include="Microsoft.AspNetCore.OpenApi" />
<!-- Versions defined in Directory.Packages.props -->
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
```
**Opt-out**: `src/Umbraco.Web.UI/Umbraco.Web.UI.csproj` sets `<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>` and specifies versions inline (for `Microsoft.EntityFrameworkCore.Design`, `Microsoft.Build.Tasks.Core`, `Microsoft.ICU.ICU4C.Runtime`, etc.). Update those versions directly in that csproj when bumping. Two further `Directory.Packages.props` files exist under `templates/` for the project/extension templates and have their own version sets — keep `Microsoft.AspNetCore.OpenApi` aligned between the root file and `templates/UmbracoExtension/`.
### Build Configuration
- `Directory.Build.props` - Shared properties (target framework, company, copyright)
- `.editorconfig` - Code style rules
- `.globalconfig` - Roslyn analyzer rules
### Persistence Layer - NPoco and EF Core
The repository contains BOTH (actively supported):
- **Current**: NPoco-based persistence (`Umbraco.Cms.Persistence.Sqlite`, `Umbraco.Cms.Persistence.SqlServer`) - widely used and fully supported
- **Future**: EF Core-based persistence (`Umbraco.Cms.Persistence.EFCore.*`) - migration in progress
**Note**: The codebase is actively migrating to EF Core, but NPoco remains the primary persistence layer and is not deprecated. Both are fully supported.
### Authentication: OpenIddict
All APIs use **OpenIddict** (OAuth 2.0/OpenID Connect):
- Reference tokens (not JWT) for better security
- **Secure cookie-based token storage** (v17+) - tokens stored in HTTP-only cookies with `__Host-` prefix
- Tokens are redacted from client-side responses and passed via secure cookies only (`[redacted]` placeholder)
- ASP.NET Core Data Protection for token encryption
- Configured in `Umbraco.Cms.Api.Common`
- API requests must include credentials (`credentials: include` for fetch)
**Load Balancing Requirement**: All servers must share the same Data Protection key ring.
**Frontend auth pitfalls** — see `src/Umbraco.Web.UI.Client/docs/edge-cases.md` (Auth & Cross-tab section) and `docs/security.md`. Key points:
- Never call `validateToken()` per API request — it revokes the previous reference token (ID2019 errors)
- `window.opener` is set for ANY `window.open()` target, not only OAuth popups — scope guards to the pathname too
- BroadcastChannel does not deliver messages to the sender's own tab
### Content Caching Strategy
**HybridCache** (`Umbraco.PublishedCache.HybridCache`):
- In-memory cache + distributed cache support
- Published content only (not draft)
- Invalidated via notifications and cache refreshers
### API Versioning
APIs use `Asp.Versioning.Mvc`:
- Management API: `/umbraco/management/api/v{version}/*`
- Delivery API: `/umbraco/delivery/api/v{version}/*`
- OpenAPI docs: `/umbraco/openapi/management.json`, `/umbraco/openapi/delivery.json`
- Swagger UI: `/umbraco/openapi/`
### Updating `OpenApi.json` (Management API)
When a PR changes Management API controllers or models, the `OpenApi.json` file in the Management API project must be updated:
1. Run the Umbraco instance locally
2. Open Swagger UI and navigate to the swagger.json link (e.g. `https://localhost:44339/umbraco/swagger/management/swagger.json`)
3. Copy the full JSON content and paste it into `src/Umbraco.Cms.Api.Management/OpenApi.json`
**Important**: Commit only the substantive changes — not IDE-applied formatting (whitespace, reordering, etc.). Extraneous formatting diffs make PRs harder to review and merge-ups more error-prone.
### Backoffice npm Package
The backoffice is published to npm as `@umbraco-cms/backoffice`. Runtime dependencies are provided via importmap; npm peerDependencies provide types only. For full details on dependency hoisting, version range logic, and plugin development, see `/src/Umbraco.Web.UI.Client/CLAUDE.md` → "npm Package Publishing".
### SQL Server 2100-parameter limit
Any `WHERE IN (@0, @1, ...)` built from a runtime-sized collection risks hitting SQL Server's 2100-parameter ceiling and throwing `SqlException` 8003 in production.
Batch with `IEnumerable<T>.InGroupsOf(Constants.Sql.MaxParameterCount)` or `Database.FetchByGroups(...)` whenever the collection size is driven by user data — not just when it currently fits. Watch for products of two scaling dimensions (documents × languages, properties × versions) and config-tunable batch sizes whose defaults are safe but ceilings aren't.
Full guidance, safe patterns and decision rule: see `/src/Umbraco.Infrastructure/CLAUDE.md` → "Avoiding the SQL Server 2100-parameter limit".
### Known Limitations
1. **Circular Dependencies**: Avoided via `Lazy<T>` or event notifications
2. **Multi-Server**: Requires shared Data Protection key ring and synchronized clocks (NTP)
3. **Database Support**: SQL Server, SQLite
---
## 7. CI/CD — Claude AI Assistant
Two GitHub Actions workflows powered by `anthropics/claude-code-action@v1`. Advisory only — does not block merging.
### Workflows
| File | Trigger | Purpose |
|------|---------|---------|
| `claude-review.yml` | `pull_request: [opened, ready_for_review]` | Auto-review every non-draft PR using the `umb-review` skill |
| `claude.yml` | `@claude` comments, issue assign/label | Interactive assistant for PRs and issues |
### Auto-Review (`claude-review.yml`)
Runs the full `.claude/skills/umb-review/SKILL.md` procedure on every newly opened or un-drafted PR. Produces inline comments per finding and one summary comment with a verdict. Skips draft PRs. No turn limit.
### Interactive (`claude.yml`)
Responds to `@claude` mentions on PRs and issues. The trigger phrase is stripped before Claude sees the message, so:
- `@claude review` → light review using `gh pr diff` (not the umb-review skill)
- `@claude fix ...` → implements a fix on a new branch
- `@claude help` → answers questions about the codebase
- `@claude label` → applies labels
- `@claude` (empty) → defaults to `review` on PRs, `help` on issues
Also triggers on issue assignment to `claude` or adding the `claude` label. Gated: only runs when `@claude` appears in the comment/issue body. Max 25 turns.
**Allowed Bash tools**: `gh`, `git`, `npm`, `dotnet` (interactive only; auto-review allows `gh` and `git`).
### Labels
Both workflows apply labels based on content:
**On PRs** (based on changed files):
| Label | Condition |
|-------|-----------|
| `area/frontend` | Files under `src/Umbraco.Web.UI.Client/` |
| `area/backend` | `.cs` files outside the frontend client |
| `area/test` | Only test files changed |
| `category/api` | Management or Delivery API files |
| `category/breaking` | Breaking changes detected |
| `category/localization` | Localization/language files |
| `category/test-automation` | Only test files changed |
| `category/refactor` | Pure refactoring, no new features |
| `category/performance` | Performance-related changes |
| `category/ux` | User-facing changes |
| `category/ui` | UI layer changes |
**On Issues** (based on content): same `area/*` and `category/*` labels, plus `affected/v14` through `affected/v17` and `affected/backoffice`.
Labels are only added, never removed. Claude applies only labels it is confident about.
### Key Implementation Notes
- **Checkout required** — the action internally runs `git fetch origin main` for trusted file restoration. Without `actions/checkout`, it fails with `fatal: not a git repository`.
- **`id-token: write` permission** — required for OIDC token exchange with the Claude GitHub App.
- **Trigger phrase stripping** — the action strips `@claude` from comments before passing to Claude. Prompts must reference commands without the prefix (e.g., `review` not `@claude review`).
- **PR number injection** — the interactive workflow injects the PR/issue number into the prompt via `${{ github.event.issue.number }}` since Claude can't discover it from `gh pr view` when checked out on `main`.
---
## 8. Code Comment Policy
**Default to no comment.** Applies to all code in this repository — C#, TypeScript, Razor, build scripts. Well-named identifiers and small functions are the primary form of self-documentation; comments are a fallback for the rare cases where the code itself cannot carry the meaning.
### When NOT to comment
- **Don't restate what the code does.** A line calling `resetState()` does not need `// Reset state`. A method named `validateInput` does not need `// Validate input`.
- **Don't narrate a sequence of calls.** If three lines run in order, the order is in the code — don't paraphrase it above.
- **Don't reference the current task, fix, callers, or PR.** No `// Fix for X`, `// Used by Y`, `// Added for the Z flow`, `// See PR #1234`. That belongs in commit messages and PR descriptions; in source it rots as the codebase evolves.
### When a comment IS justified
Write a comment only when **removing it would leave a future reader confused**. Concretely:
- **A non-obvious WHY.** A hidden constraint, business rule, or ordering requirement that is not visible from the code.
- **A workaround for a specific bug or platform quirk.** Link the issue (`(#21996)`, `https://...`) so the comment can be deleted once the upstream fix lands.
- **A subtle invariant** that the type system or method names do not enforce.
- **An edge case the code intentionally handles** that would surprise a reader (e.g. "must run before X because Y").
- **API documentation** — XML doc comments on C# members, JSDoc on exported TypeScript symbols. Required for the public contract; still keep them concise.
### TODOs
Allowed, but cheap to write and cheaper to leave behind. Keep them short and trackable: `// TODO (V19): remove once obsolete overload is gone` or `// TODO: pagination [NL]`. A TODO should have an author or a version trigger.
---
## 9. Testing Practices
### Tests for a bug fix must fail before the fix
Verify any test you add for a bug fix actually catches the bug: either write the failing test first (TDD), or temporarily revert the production change and confirm the test fails before re-applying. A test that passes both ways proves nothing. Watch for coincidental passes — default seed/sort orders can make a buggy path produce the right answer for the test's specific inputs; construct inputs so the broken and fixed behaviours give visibly different results.
For integration tests that exercise caching or cache refreshers, see `tests/Umbraco.Tests.Integration/CLAUDE.md` — the harness disables caching by default, which can produce false greens.
---
## Quick Reference
### Essential Commands
```bash
# Build solution
dotnet build
# Run all tests
dotnet test
# Run specific test category
dotnet test --filter "Category=Integration"
# Format code
dotnet format
# Pack all projects
dotnet pack -c Release
```
### Integration Test Database Configuration
Integration tests are configured in `tests/Umbraco.Tests.Integration/appsettings.Tests.json`.
The `Tests:Database:DatabaseType` setting controls which database is used:
- `"SQLite"` (default) - No external dependencies
- `"LocalDb"` - Uses SQL Server LocalDB, required for SQL Server-specific tests (e.g., page-level locking, `sys.dm_tran_locks`)
SQL Server-specific tests use `BaseTestDatabase.IsSqlite()` to skip when running on SQLite.
### Key Projects
| Project | Type | Description |
|---------|------|-------------|
| **Umbraco.Core** | Library | Interface contracts and domain models |
| **Umbraco.Infrastructure** | Library | Service implementations and data access |
| **Umbraco.Web.UI** | Application | Main web application (Razor/MVC) |
| **Umbraco.Cms.Api.Management** | Library | Management API (backoffice) |
| **Umbraco.Cms.Api.Delivery** | Library | Delivery API (headless CMS) |
| **Umbraco.Cms.Api.Common** | Library | Shared API infrastructure |
| **Umbraco.PublishedCache.HybridCache** | Library | Published content caching |
| **Umbraco.Examine.Lucene** | Library | Full-text search indexing |
### Important Files
- **Solution**: `umbraco.sln`
- **Build Config**: `Directory.Build.props`, `Directory.Packages.props`
- **Code Style**: `.editorconfig`, `.globalconfig`
- **Documentation**: `/CLAUDE.md`, `/src/Umbraco.Core/CLAUDE.md`, `/src/Umbraco.Cms.Api.Common/CLAUDE.md`
### Project-Specific Documentation
For detailed information about individual projects, see their CLAUDE.md files:
- **Core Architecture**: `/src/Umbraco.Core/CLAUDE.md` - Service contracts, notification patterns
- **API Infrastructure**: `/src/Umbraco.Cms.Api.Common/CLAUDE.md` - OpenAPI, authentication, serialization
- **Backoffice Frontend**: `/src/Umbraco.Web.UI.Client/CLAUDE.md` - Lit web components, extension system, auth client
**Important**: When working on backoffice client code (anything under `src/Umbraco.Web.UI.Client/`), read `/src/Umbraco.Web.UI.Client/CLAUDE.md` first. It contains action-specific checklists (deprecation, testing, security, etc.) that are not duplicated here.
### Getting Help
- **Official Docs**: https://docs.umbraco.com/
- **Contributing Guide**: `.github/CONTRIBUTING.md`
- **Issues**: https://github.com/umbraco/Umbraco-CMS/issues
- **Community**: https://forum.umbraco.com/
- **Releases**: https://releases.umbraco.com/
---
**This repository follows a layered architecture with strict dependency rules. The Core defines contracts, Infrastructure implements them, and Web/APIs consume them. Each layer can be understood independently, but dependencies always flow inward toward Core.**
-77
View File
@@ -1,77 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Company>Umbraco HQ</Company>
<Authors>Umbraco</Authors>
<Copyright>Copyright © Umbraco $([System.DateTime]::Today.ToString('yyyy'))</Copyright>
<Product>Umbraco CMS</Product>
<PackageProjectUrl>https://umbraco.com/</PackageProjectUrl>
<PackageIconUrl>https://umbraco.com/dist/nuget/logo-small.png</PackageIconUrl>
<PackageIcon>icon.png</PackageIcon>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageTags>umbraco</PackageTags>
<NeutralLanguage>en-US</NeutralLanguage>
<Nullable>enable</Nullable>
<WarningsAsErrors>nullable</WarningsAsErrors>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<WarnOnPackingNonPackableProject>false</WarnOnPackingNonPackableProject>
</PropertyGroup>
<PropertyGroup>
<!--
TODO: Fix and remove overrides:
[NU5104] Warning As Error: A stable release of a package should not have a prerelease dependency. Either modify the version spec of dependency
-->
<NoWarn>$(NoWarn),NU5104,SA1309</NoWarn>
<WarningsNotAsErrors>$(WarningsNotAsErrors),NU5104,SA1600</WarningsNotAsErrors>
</PropertyGroup>
<!-- SourceLink -->
<PropertyGroup>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<!-- Package Validation -->
<PropertyGroup>
<GenerateCompatibilitySuppressionFile>false</GenerateCompatibilitySuppressionFile>
<EnablePackageValidation>true</EnablePackageValidation>
<PackageValidationBaselineVersion>18.0.0</PackageValidationBaselineVersion>
<EnableStrictModeForCompatibleFrameworksInPackage>true</EnableStrictModeForCompatibleFrameworksInPackage>
<EnableStrictModeForCompatibleTfms>true</EnableStrictModeForCompatibleTfms>
</PropertyGroup>
<!-- Calculate version only once for the whole repository -->
<PropertyGroup>
<GitVersionBaseDirectory>$(MSBuildThisFileDirectory)</GitVersionBaseDirectory>
</PropertyGroup>
<!-- Include icon in generated NuGet packages -->
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)icon.png" Pack="true" PackagePath="" Visible="false" />
</ItemGroup>
<!-- Use version range on project references (to limit on major version in generated packages) -->
<Target Name="_GetProjectReferenceVersionRanges" AfterTargets="_GetProjectReferenceVersions">
<ItemGroup>
<_ProjectReferencesWithVersions Condition="'%(ProjectVersion)' != ''">
<ProjectVersion>[%(ProjectVersion), $([MSBuild]::Add($([System.Text.RegularExpressions.Regex]::Match('%(ProjectVersion)', '^\d+').Value), 1)))</ProjectVersion>
</_ProjectReferencesWithVersions>
</ItemGroup>
</Target>
<!-- Workaround for https://github.com/umbraco/Umbraco-CMS/issues/23018
Due to the amount of XML documentation in this solution, the OpenAPI XML documentation source generator produces
too many lines of code causing a StackOverflowException when running on IIS. For that reason we disable the analyzer.
See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/openapi/openapi-comments?view=aspnetcore-10.0#disabling-xml-documentation-support -->
<Target Name="DisableCompileTimeOpenApiXmlGenerator" BeforeTargets="CoreCompile" Condition="'$(IsPackable)' != 'false' or '$(IsTestProject)' == 'true'">
<ItemGroup>
<Analyzer Remove="@(Analyzer)" Condition="'%(Filename)' == 'Microsoft.AspNetCore.OpenApi.SourceGenerators'" />
</ItemGroup>
</Target>
</Project>
-98
View File
@@ -1,98 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
<!-- Global packages (private, build-time packages for all projects) -->
<ItemGroup>
<GlobalPackageReference Include="Nerdbank.GitVersioning" Version="3.9.50" />
<GlobalPackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<!-- TODO (V18): Bump Umbraco.Code to 3.0.0 stable before release of 18.0.0 -->
<GlobalPackageReference Include="Umbraco.Code" Version="3.0.0-beta" />
<GlobalPackageReference Include="Umbraco.GitVersioning.Extensions" Version="0.2.0" />
</ItemGroup>
<!-- Microsoft packages -->
<ItemGroup>
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.7" />
<!-- When updating this version, also update templates/UmbracoExtension/Umbraco.Extension.csproj -->
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.7" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="5.3.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.3.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Identity.Core" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Identity.Stores" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Options.DataAnnotations" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Caching.Hybrid" Version="10.5.0" />
<PackageVersion Include="System.Linq.Async" Version="7.0.1" />
</ItemGroup>
<!-- Umbraco packages -->
<ItemGroup>
<PackageVersion Include="Umbraco.JsonSchema.Extensions" Version="0.4.0" />
</ItemGroup>
<!-- Third-party packages -->
<ItemGroup>
<PackageVersion Include="Asp.Versioning.Mvc" Version="10.0.0" />
<PackageVersion Include="Asp.Versioning.Mvc.ApiExplorer" Version="10.0.0" />
<PackageVersion Include="Dazinator.Extensions.FileProviders" Version="2.0.0" />
<PackageVersion Include="Examine" Version="3.8.0" />
<PackageVersion Include="Examine.Core" Version="3.8.0" />
<PackageVersion Include="HtmlAgilityPack" Version="1.12.4" />
<PackageVersion Include="JsonPatch.Net" Version="3.3.0" />
<PackageVersion Include="K4os.Compression.LZ4" Version="1.3.8" />
<PackageVersion Include="MailKit" Version="4.16.0" />
<PackageVersion Include="Markdig" Version="1.1.3" />
<PackageVersion Include="Markdown" Version="2.2.1" />
<PackageVersion Include="MessagePack" Version="3.1.7" />
<PackageVersion Include="MiniProfiler.AspNetCore.Mvc" Version="4.5.4" />
<PackageVersion Include="MiniProfiler.Shared" Version="4.5.4" />
<PackageVersion Include="ncrontab" Version="3.4.0" />
<PackageVersion Include="NPoco" Version="6.2.0" />
<PackageVersion Include="NPoco.SqlServer" Version="6.2.0" />
<PackageVersion Include="OpenIddict.Abstractions" Version="7.5.0" />
<PackageVersion Include="OpenIddict.AspNetCore" Version="7.5.0" />
<PackageVersion Include="OpenIddict.EntityFrameworkCore" Version="7.5.0" />
<PackageVersion Include="Serilog" Version="4.3.1" />
<PackageVersion Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageVersion Include="Serilog.Enrichers.Process" Version="3.0.0" />
<PackageVersion Include="Serilog.Enrichers.Thread" Version="4.0.0" />
<PackageVersion Include="Serilog.Expressions" Version="5.0.0" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="10.0.0" />
<PackageVersion Include="Serilog.Formatting.Compact" Version="3.0.0" />
<PackageVersion Include="Serilog.Formatting.Compact.Reader" Version="4.0.0" />
<PackageVersion Include="Serilog.Settings.Configuration" Version="10.0.0" />
<PackageVersion Include="Serilog.Sinks.Async" Version="2.1.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageVersion Include="Serilog.Sinks.Map" Version="2.0.0" />
<PackageVersion Include="SixLabors.ImageSharp" Version="3.1.12" />
<PackageVersion Include="SixLabors.ImageSharp.Web" Version="3.2.0" />
<PackageVersion Include="Swashbuckle.AspNetCore.SwaggerUI" Version="10.1.7" />
</ItemGroup>
<!-- Transitive pinned versions (only required because our direct dependencies have vulnerable versions of transitive dependencies) -->
<ItemGroup>
<!-- Dazinator.Extensions.FileProviders references vulnerable versions of the following: -->
<!-- TODO (V18): Remove these pinned dependencies when the Dazinator.Extensions.FileProviders dependency is removed. -->
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
<!-- Markdown references vulnerable version of the following: -->
<!-- TODO (V19): Remove these pinned dependencies when the Markdown dependency is removed. -->
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
<!-- Examine (via Microsoft.AspNetCore.DataProtection 8.0.4) references a vulnerable version of the following: -->
<!-- TODO: Remove this pinned dependency when Examine updates its Microsoft.AspNetCore.DataProtection reference. -->
<PackageVersion Include="System.Security.Cryptography.Xml" Version="10.0.7" />
</ItemGroup>
</Project>
-144
View File
@@ -1,144 +0,0 @@
# MCP (Model Context Protocol) Setup
This repository includes configuration for [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) servers, enabling AI tooling integration for Umbraco CMS development workflows.
## Overview
MCP allows AI assistants (like Claude) to interact with external tools and services. This repository configures two MCP servers:
| Server | Purpose | Package |
|--------|---------|---------|
| **umbraco-cms** | Manage Umbraco content types, documents, and media | `@umbraco-cms/mcp-dev@17` |
| **playwright** | Browser automation for testing and debugging | `@playwright/mcp@latest` |
## Quick Start
### 1. Start Umbraco Locally
Ensure your local Umbraco instance is running at `https://localhost:44339` (or update the URL in your `.env.local`).
### 2. Configure Environment Variables
Copy the example environment file and customize it:
```bash
cp .env.example .env.local
```
Edit `.env.local` with your local settings:
```env
UMBRACO_CLIENT_ID=umbraco-back-office-mcp
UMBRACO_CLIENT_SECRET=<your-client-secret>
UMBRACO_BASE_URL=https://localhost:44339
NODE_TLS_REJECT_UNAUTHORIZED=0
UMBRACO_INCLUDE_TOOL_COLLECTIONS=data-type,document-type,document,media-type,media
```
### 3. Configure the OAuth Client in Umbraco
Create an OAuth client in your Umbraco instance with:
- **Client ID**: `umbraco-back-office-mcp`
- **Client Secret**: The value you set in `.env.local`
- **Grant Type**: Client Credentials
## Environment Variables Reference
| Variable | Description | Example |
|----------|-------------|---------|
| `UMBRACO_CLIENT_ID` | OAuth client ID configured in Umbraco | `umbraco-back-office-mcp` |
| `UMBRACO_CLIENT_SECRET` | OAuth client secret (keep secure!) | `your-secure-secret` |
| `UMBRACO_BASE_URL` | URL of your local Umbraco instance | `https://localhost:44339` |
| `NODE_TLS_REJECT_UNAUTHORIZED` | Set to `0` for self-signed certificates (local dev only) | `0` |
| `UMBRACO_INCLUDE_TOOL_COLLECTIONS` | Comma-separated list of tool collections to enable | `data-type,document-type,document` |
### Tool Collections
The `UMBRACO_INCLUDE_TOOL_COLLECTIONS` variable controls which Umbraco MCP tools are available:
- `data-type` - Manage data types (property editors)
- `document-type` - Manage document types (content types)
- `document` - Manage content/documents
- `media-type` - Manage media types
- `media` - Manage media items
## Security Considerations
> **Warning**: This configuration is for **local development only**.
### Self-Signed Certificates
`NODE_TLS_REJECT_UNAUTHORIZED=0` disables SSL certificate validation. This is necessary for self-signed certificates in local development but:
- **Never use in production**
- Affects all HTTPS connections made by Node.js processes
- Consider trusting your local development certificate instead
### Client Secrets
- Never commit real secrets to source control
- The `.env.local` file is gitignored for this reason
- Use strong, unique secrets even in development
- The example value `1234567890` in `.env.example` is a placeholder only
## File Structure
```
Umbraco-CMS/
├── .mcp.json # MCP server configuration
├── .env.example # Example environment variables (committed)
├── .env.local # Your local environment variables (gitignored)
├── .claude/
│ ├── settings.json # Shared Claude AI permissions (committed)
│ └── settings.local.json # Local Claude overrides (gitignored)
├── .gitignore # Ignores .env.local and settings.local.json
└── MCP.md # This documentation (you are here)
```
## Claude AI Permissions
The `.claude/settings.json` file configures which MCP tools Claude can use automatically without prompting. This is shared across the team for consistent developer experience.
### Customizing Permissions Locally
Create `.claude/settings.local.json` to override permissions for your environment:
```json
{
"permissions": {
"allow": [
"mcp__umbraco__get-all-document-types"
]
}
}
```
## Troubleshooting
### "Connection refused" errors
- Ensure Umbraco is running at the configured `UMBRACO_BASE_URL`
- Check that the port matches your local setup
### "Unauthorized" errors
- Verify the OAuth client is configured in Umbraco
- Check that `UMBRACO_CLIENT_ID` and `UMBRACO_CLIENT_SECRET` match
- Ensure the client has appropriate permissions
### "Certificate" errors
- For local development, set `NODE_TLS_REJECT_UNAUTHORIZED=0` in `.env.local`
- Alternatively, trust your local development certificate
### MCP server not starting
- Ensure Node.js is installed (v22+ recommended, matching .nvmrc)
- Run `npx @umbraco-cms/mcp-dev@17 --help` to verify the package works
## Further Reading
- [Model Context Protocol Documentation](https://modelcontextprotocol.io/)
- [Umbraco MCP Package](https://www.npmjs.com/package/@umbraco-cms/mcp-dev)
- [Playwright MCP](https://www.npmjs.com/package/@playwright/mcp)
- [Claude Code Documentation](https://docs.anthropic.com/claude-code)
-541
View File
@@ -1,541 +0,0 @@
Third-Party Notices
===================
This file contains notices and attributions for third-party software used in the Umbraco CMS project.
Third-party software may contain dependencies that are not explicitly listed here.
This notice is not a license and does not grant any rights to use the third-party software.
Umbraco CMS is licensed under the MIT License, which can be found in the LICENSE file.
---
@openid/AppAuth-JS: An OpenID Connect and OAuth 2.0 client library for JavaScript
URL: https://github.com/openid/AppAuth-JS
License: Apache License, Version 2.0
Copyright: 2017 Google Inc.
---
AutoFixture: Write maintainable unit tests, faster
URL: https://github.com/AutoFixture/AutoFixture
License: MIT License
Copyright: 2013 Mark Seemann
---
Asp.Versioning.Mvc: A library for ASP.NET Core versioning
URL: https://github.com/dotnet/aspnet-api-versioning
License: MIT License
Copyright: .NET Foundation and contributors
---
Babel: A JavaScript compiler
URL: https://babeljs.io/
License: MIT License
Copyright: 2014-present Sebastian McKenzie and other contributors
---
BenchmarkDotNet: Powerful .NET library for benchmarking
URL: https://github.com/dotnet/BenchmarkDotNet
License: MIT License
Copyright: .NET Foundation and Contributors
---
Bogus: A simple and sane data generator for populating objects that supports different locales.
URL: https://github.com/bchavez/Bogus
License: MIT License
Copyright: 2015 Brian Chavez
---
CommandLineParser: Terse syntax C# command line parser for .NET
URL: https://github.com/commandlineparser/commandline
License: MIT License
Copyright: 2005-2015 Giacomo Stelluti Scala & Contributors
---
cross-env: A CLI tool to set environment variables across platforms
URL: https://github.com/kentcdodds/cross-env
License: MIT License
Copyright: 2017 Kent C. Dodds
---
Dazinator.Extensions.FileProviders: A library for file provider extensions
URL: https://github.com/dazinator/Dazinator.Extensions.FileProviders
License: MIT License
Copyright: 2016 Darrell
---
DOMPurify: A DOM-only XSS sanitizer for HTML, MathML and SVG
URL: https://github.com/cure53/DOMPurify
License: Apache License, Version 2.0
Copyright: 2025 Dr.-Ing. Mario Heiderich, Cure53
---
Element Internals Polyfill: A polyfill for the Element Internals API
URL: https://github.com/calebdwilliams/element-internals-polyfill
License: MIT License
Copyright: 2021 Caleb Williams
---
Eslint: A tool for identifying and reporting on patterns in JavaScript
URL: https://eslint.org/
License: MIT License
Copyright: OpenJS Foundation and other contributors
---
Examine: A search and indexing library for .NET
URL: https://github.com/Shazwazza/Examine
License: Microsoft Public License (Ms-PL)
Copyright: 2023 Shannon Deminick
---
Globals: A library for managing global variables in JavaScript
URL: https://github.com/sindresorhus/globals
License: MIT License
Copyright: Sindre Sorhus
---
Html Agility Pack: An HTML parser for .NET
URL: https://html-agility-pack.net/
License: MIT License
Copyright: ZZZ Projects Inc.
---
ImageSharp: A cross-platform library for processing images in .NET
URL: https://github.com/SixLabors/ImageSharp
License: Apache License, Version 2.0 under the Six Labors Split License
Copyright: Six Labors
---
jsdiff: A JavaScript text differencing implementation
URL: https://github.com/kpdecker/jsdiff
License: BSD 3-Clause License
Copyright: 2009-2015 Kevin Decker <kpdecker@gmail.com>
---
JsonPatch.Net: A library for JSON Patch (RFC 6902) in .NET
URL: https://github.com/json-everything/json-everything
License: MIT License
Copyright: .NET Foundation and Contributors
---
K4os.Compression.LZ4: A fast LZ4 compression library for .NET
URL: https://github.com/MiloszKrajewski/K4os.Compression.LZ4
License: MIT License
Copyright: 2017 Milosz Krajewski
---
Lit: A simple library for building fast, lightweight web components
URL: https://lit.dev
License: BSD 3-Clause License
Copyright: 2020 Google LLC. All rights reserved.
---
Lucide: Beautiful & consistent icons for the web
URL: https://lucide.dev/
License: ISC License
Copyright: 2013-2022 Cole Bemis
Copyright: 2022 Lucide Contributors
---
Madge: A dependency graph generator for JavaScript
URL: https://github.com/pahen/madge
License: MIT License
Copyright: 2017 Patrik Henningsson
---
MailKit: A library for sending email in .NET
URL: https://github.com/jstedfast/MailKit
License: MIT License
Copyright: 2013-2024 .NET Foundation and Contributors
---
Markdig: A fast, powerful, CommonMark compliant, extensible Markdown processor for .NET
URL: https://github.com/xoofx/markdig
License: BSD-2-Clause license
Copyright: 2018+, Alexandre Mutel. All rights reserved.
---
Markdown: A library for parsing and compiling Markdown
URL: https://github.com/hey-red/Markdown
License: MIT License
Copyright: 2018 red
---
marked: A markdown parser and compiler
URL: https://marked.js.org/
License: MIT License
Copyright: 2011-2018, Christopher Jeffrey (https://github.com/chjj/)
Copyright: 2018+, MarkedJS (https://github.com/markedjs/)
---
Message Pack: The extremely fast MessagePack serializer for C#
URL: https://github.com/MessagePack-CSharp/MessagePack-CSharp
License: MIT License
Copyright: 2017 Yoshifumi Kawai and contributors
---
Miniprofiler: A mini profiler for .NET
URL: https://github.com/MiniProfiler/dotnet
License: MIT License
Copyright: .NET MiniProfiler Contributors
---
Monaco Editor: A browser-based code editor
URL: https://microsoft.github.io/monaco-editor/
License: MIT License
Copyright: 2016-present Microsoft Corporation
---
Moq: A mocking library for .NET
URL: https://github.com/moq/moq
License: BSD 3-Clause License
Copyright: 2007 Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors.
---
Mock Service Worker (MSW): A library for mocking API requests in JavaScript
URL: https://mswjs.io/
License: MIT License
Copyright: 2018present Artem Zakharchenko
---
NCrontab: A cron schedule parser for .NET
URL: https://github.com/atifaziz/NCrontab
License: Apache License, Version 2.0
Copyright: 2001 The OpenSymphony Group
Copyright: 2008 Atif Aziz
---
Nerdbank.GitVersioning: A library for versioning .NET projects
URL: https://github.com/dotnet/Nerdbank.GitVersioning
License: MIT License
Copyright: .NET Foundation and Contributors
---
NJsonSchema: A JSON schema validator for .NET
URL: https://github.com/RicoSuter/NJsonSchema
License: MIT License
Copyright: 2022 Rico Suter
---
NPoco: A micro ORM for .NET
URL: https://github.com/schotime/NPoco
License: Apache License, Version 2.0
Copyright: Schotime
---
NUnit: A unit testing framework for .NET
URL: https://github.com/nunit/nunit
License: MIT License
Copyright: Charlie Poole, Rob Prouse and Contributors
---
Open Web Components: A set of standards and libraries for building web components
URL: https://open-wc.org/
License: MIT License
Copyright: 2018 open-wc
---
Openapi-ts: The OpenAPI to TypeScript codegen
URL: https://github.com/hey-api/openapi-ts
License: MIT License
Copyright: Hey API
---
OpenIddict: A simple and flexible OpenID Connect server for ASP.NET Core
URL: https://github.com/openiddict/openiddict-core
License: Apache License, Version 2.0
Copyright: Kévin Chalet
---
Playwright: A Node.js library to automate browser testing
URL: https://playwright.dev/
License: Apache License, Version 2.0
Copyright: 2025 Microsoft Corporation
---
Playwright-msw: A library to wrap Mock Service Worker with Playwright
URL: https://github.com/valendres/playwright-msw
License: MIT License
Copyright: 2022 Peter Weller
---
Prettier: An opinionated code formatter
URL: https://prettier.io/
License: MIT License
Copyright: James Long and contributors
---
Remark-gfm: A GitHub Flavored Markdown plugin for Remark
URL: https://github.com/remarkjs/remark-gfm
License: MIT License
Copyright: Titus Wormer
---
rxjs: Reactive Extensions for JavaScript
URL: https://rxjs.dev/
License: Apache License, Version 2.0
Copyright: 2015-present Ben Lesh <ben@benlesh.com>, Google, Inc., Netflix, Inc., Microsoft Corp., and contributors
---
Serilog: A diagnostic logging library for .NET
URL: https://github.com/serilog/serilog
License: Apache License, Version 2.0
Copyright: Serilog Contributors
---
Simple Icons: A set of SVG icons for popular brands
URL: https://simpleicons.org/
License: CC0 1.0 Universal License
Copyright: Simple Icons Contributors
---
Storybook: A UI component explorer for Web Components
URL: https://storybook.js.org/
License: MIT License
Copyright: 2024 Storybook
---
StyleCop.Analyzers: Analyzers for StyleCop
URL: https://github.com/DotNetAnalyzers/StyleCopAnalyzers
License: MIT License
Copyright: Tunnel Vision Laboratories, LLC
---
SVGO: A tool for optimizing SVG files
URL: https://svgo.dev/
License: MIT License
Copyright: Kir Belevich
---
Swashbuckle.AspNetCore: A library for generating Swagger documentation for ASP.NET Core APIs
URL: https://github.com/domaindrivendev/Swashbuckle.AspNetCore
License: MIT License
Copyright: 2016 Richard Morris
---
Tiny Glob: A tiny globbing library for Node.js
URL: https://github.com/terkelg/tiny-glob
License: MIT License
Copyright: 2018 Terkel
---
Tiptap: A renderless rich-text editor for the web
URL: https://tiptap.dev/
License: MIT License
Copyright: 2025 Tiptap GmbH
---
Tsc-alias: A TypeScript compiler plugin for aliasing module paths
URL: https://github.com/justkey007/tsc-alias
License: MIT License
Copyright: 2018 Justkey
---
Typedoc: A documentation generator for TypeScript projects
URL: https://typedoc.org/
License: Apache License, Version 2.0
Copyright: Gerrit Birkeland and Contributors
---
Typescript: A typed superset of JavaScript that compiles to plain JavaScript
URL: https://www.typescriptlang.org/
License: Apache License, Version 2.0
Copyright: 2012-present Microsoft Corporation
---
Typescript-eslint: A set of tools for linting TypeScript code
URL: https://github.com/typescript-eslint/typescript-eslint
License: MIT License
Copyright: 2019 typescript-eslint and other contributors
---
Typescript-json-schema: A library for generating JSON schema from TypeScript types
URL: https://github.com/YousefED/typescript-json-schema
License: BSD 3-Clause License
Copyright: 2016 typescript-json-schema contributors
---
Umbraco.Code: Provides code-level tools for Umbraco
URL: https://github.com/umbraco/Umbraco-Code
License: MIT License
Copyright: 2005-present Umbraco A/S
---
Umbraco.GitVersioning.Extensions: Utilities for Nerdbank.GitVersioning
URL: https://github.com/umbraco/Umbraco.GitVersioning.Extensions
License: MIT License
Copyright: 2005-present Umbraco A/S
---
Umbraco.JsonSchema.Extensions: Utilities for JSON schema generation
URL: https://github.com/umbraco/Umbraco.JsonSchema.Extensions
License: MIT License
Copyright: 2005-present Umbraco A/S
---
Umbraco UI Library: A set of UI components for building web applications
URL: https://uui.umbraco.com/
License: MIT License
Copyright: 2005-present Umbraco A/S
---
uuid: A library for generating unique identifiers
URL: https://github.com/uuidjs/uuid
License: MIT License
Copyright: 2010-2020 Robert Kieffer and other contributors
---
Vite: A fast build tool and development server for modern web projects
URL: https://vite.dev/
License: MIT License
Copyright: 2019-present VoidZero Inc. and Vite contributors
---
Vite-plugin-static-copy: A Vite plugin for copying static files
URL: https://github.com/sapphi-red/vite-plugin-static-copy
License: MIT License
Copyright: 2021 sapphi-red
---
Vite-tsconfig-paths: A Vite plugin for resolving TypeScript paths
URL: https://github.com/aleclarson/vite-tsconfig-paths
License: MIT License
Copyright: Alec Larson
---
Web Component Analyzer: A tool for analyzing web components
URL: https://github.com/runem/web-component-analyzer
License: MIT License
Copyright: 2019 Rune Mehlsen
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--
this is Umbraco's NuGet configuration,
content of this file is merged with the system-wide configuration,
at %APPDATA%\NuGet\NuGet.config
-->
<packageSources>
<add key="UmbracoCoreMyGet" value="https://www.myget.org/F/umbracocore/api/v3/index.json" />
</packageSources>
</configuration>
-10
View File
@@ -1,10 +0,0 @@
{
"folders": [
{
"path": "src/Umbraco.Web.UI.Client"
},
{
"path": "src/Umbraco.Web.UI.Login"
}
]
}
+59
View File
@@ -0,0 +1,59 @@
Param(
[string]$GitHubPersonalAccessToken,
[string]$Directory
)
$workingDirectory = $Directory
CD "$($workingDirectory)"
# Clone repo
$fullGitUrl = "https://$($env:GIT_URL)/$($env:GIT_REPOSITORYNAME).git"
git clone $($fullGitUrl) $($env:GIT_REPOSITORYNAME) 2>&1 | % { $_.ToString() }
# Remove everything so that unzipping the release later will update everything
# Don't remove the readme file nor the git directory
Write-Host "Cleaning up git directory before adding new version"
Remove-Item -Recurse "$($workingDirectory)\$($env:GIT_REPOSITORYNAME)\*" -Exclude README.md,.git
# Find release zip
$zipsDir = "$($workingDirectory)\$($env:BUILD_DEFINITIONNAME)\zips"
$pattern = "UmbracoCms.([0-9]{1,2}.[0-9]{1,3}.[0-9]{1,3}).zip"
Write-Host "Searching for Umbraco release files in $($zipsDir) for a file with pattern $($pattern)"
$file = (Get-ChildItem "$($zipsDir)" | Where-Object { $_.Name -match "$($pattern)" })
if($file)
{
# Get release name
$version = [regex]::Match($($file.Name), $($pattern)).captures.groups[1].value
$releaseName = "Umbraco $($version)"
Write-Host "Found $($releaseName)"
# Unzip into repository to update release
Add-Type -AssemblyName System.IO.Compression.FileSystem
Write-Host "Unzipping $($file.FullName) to $($workingDirectory)\$($env:GIT_REPOSITORYNAME)"
[System.IO.Compression.ZipFile]::ExtractToDirectory("$($file.FullName)", "$($workingDirectory)\$($env:GIT_REPOSITORYNAME)")
# Telling git who we are
git config --global user.email "coffee@umbraco.com" 2>&1 | % { $_.ToString() }
git config --global user.name "Umbraco HQ" 2>&1 | % { $_.ToString() }
# Commit
CD "$($workingDirectory)\$($env:GIT_REPOSITORYNAME)"
Write-Host "Committing Umbraco $($version) Release from Build Output"
git add . 2>&1 | % { $_.ToString() }
git commit -m " Release $($releaseName) from Build Output" 2>&1 | % { $_.ToString() }
# Tag the release
git tag -a "v$($version)" -m "v$($version)"
# Push release to master
$fullGitAuthUrl = "https://$($env:GIT_USERNAME):$($GitHubPersonalAccessToken)@$($env:GIT_URL)/$($env:GIT_REPOSITORYNAME).git"
git push $($fullGitAuthUrl) 2>&1 | % { $_.ToString() }
#Push tag to master
git push $($fullGitAuthUrl) --tags 2>&1 | % { $_.ToString() }
}
else
{
Write-Error "Umbraco release file not found, searched in $($workingDirectory)\$($zipsDir) for a file with pattern $($pattern) - canceling"
}
+61
View File
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="4.1.0">
<id>UmbracoCms.Core</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>https://umbraco.com/dist/nuget/logo-small.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<repository type="git" url="https://github.com/umbraco/umbraco-cms" />
<dependencies>
<group targetFramework="net472">
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="LightInject" version="[5.4.0,5.999999)" />
<dependency id="LightInject.Annotation" version="[1.1.0,1.999999)" />
<dependency id="LightInject.Web" version="[2.0.0,2.999999)" />
<dependency id="Microsoft.AspNet.Identity.Core" version="[2.2.2,2.999999)" />
<dependency id="Microsoft.AspNet.WebApi.Client" version="[5.2.7,5.999999)" />
<dependency id="Microsoft.Owin" version="[4.0.1,4.999999)" />
<dependency id="MiniProfiler" version="[4.0.138,4.999999)" />
<dependency id="Newtonsoft.Json" version="[12.0.1,12.999999)" />
<dependency id="Semver" version="[2.0.4,2.999999)" />
<dependency id="Serilog" version="[2.10.0,2.999999)" />
<dependency id="Serilog.Enrichers.Process" version="[2.0.2,2.999999)" />
<dependency id="Serilog.Enrichers.Thread" version="[3.1.0,3.999999)" />
<dependency id="Serilog.Filters.Expressions" version="[2.1.0,2.999999)" />
<dependency id="Serilog.Formatting.Compact" version="[1.1.0,1.999999)" />
<dependency id="Serilog.Formatting.Compact.Reader" version="[1.0.5,1.999999)" />
<dependency id="Serilog.Settings.AppSettings" version="[2.2.2,2.999999)" />
<dependency id="Serilog.Sinks.File" version="[4.1.0,4.999999)" />
<dependency id="Serilog.Sinks.Map" version="[1.0.2,1.999999)" />
<dependency id="Serilog.Sinks.Async" version="[1.5.0,1.999999)" />
<dependency id="Umbraco.SqlServerCE" version="[4.0.0.1,4.999999)" />
<dependency id="NPoco" version="[3.9.4,3.999999)" />
</group>
</dependencies>
</metadata>
<files>
<!-- libs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.dll" target="lib\net472\Umbraco.Core.dll" />
<!-- docs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Core.xml" target="lib\net472\Umbraco.Core.xml" />
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib\net472\Umbraco.Core.pdb" />
</files>
</package>
+75
View File
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="4.1.0">
<id>UmbracoCms.Web</id>
<version>8.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>https://umbraco.com/dist/nuget/logo-small.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the web assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
<repository type="git" url="https://github.com/umbraco/umbraco-cms" />
<dependencies>
<group targetFramework="net472">
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="UmbracoCms.Core" version="[$version$]" />
<dependency id="ClientDependency" version="[1.9.10,1.999999)" />
<dependency id="ClientDependency-Mvc5" version="[1.9.3,1.999999)" />
<dependency id="CSharpTest.Net.Collections" version="[14.906.1403.1082,14.999999)" />
<dependency id="Examine" version="[1.2.2,1.999999)" />
<dependency id="HtmlAgilityPack" version="[1.8.14,1.999999)" />
<dependency id="ImageProcessor" version="[2.9.1,2.999999)" />
<dependency id="LightInject.Mvc" version="[2.0.0,2.999999)" />
<dependency id="LightInject.WebApi" version="[2.0.0,2.999999)" />
<dependency id="Markdown" version="[2.2.1,2.999999)" />
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.2,2.999999)" />
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.7,5.999999)" />
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.4.0,2.999999)" />
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.7,5.999999)" />
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[4.0.1,4.999999)" />
<dependency id="Microsoft.Owin.Security.Cookies" version="[4.0.1,4.999999)" />
<dependency id="Microsoft.Owin.Security.OAuth" version="[4.0.1,4.999999)" />
<dependency id="System.Buffers" version="[4.5.1,4.999999)" />
<dependency id="System.Numerics.Vectors" version="[4.5.0,4.999999)" />
<dependency id="System.Memory" version="[4.5.4,4.999999)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.9.0,4.999999)" />
<dependency id="System.Collections.Immutable" version="[1.7.1,1.999999)" />
<dependency id="System.Text.Encoding.CodePages" version="[4.7.1,4.999999)" />
<dependency id="MessagePack" version="[2.2.85,2.999999)" />
<dependency id="K4os.Compression.LZ4" version="[1.1.11,1.999999)" />
</group>
</dependencies>
</metadata>
<files>
<!-- libs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.dll" target="lib\net472\Umbraco.Web.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.dll" target="lib\net472\Umbraco.Web.UI.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.dll" target="lib\net472\Umbraco.Examine.dll" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.ModelsBuilder.Embedded.dll" target="lib\net472\Umbraco.ModelsBuilder.Embedded.dll" />
<!-- docs -->
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.xml" target="lib\net472\Umbraco.Web.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Web.UI.xml" target="lib\net472\Umbraco.Web.UI.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.Examine.xml" target="lib\net472\Umbraco.Examine.xml" />
<file src="$BuildTmp$\WebApp\bin\Umbraco.ModelsBuilder.Embedded.xml" target="lib\net472\Umbraco.ModelsBuilder.Embedded.xml" />
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib\net472\Umbraco.Web.pdb" />
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib\net472\Umbraco.Examine.pdb" />
<file src="$BuildTmp$\bin\Umbraco.ModelsBuilder.Embedded.pdb" target="lib\net472\Umbraco.ModelsBuilder.Embedded.pdb" />
</files>
</package>
+68
View File
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata minClientVersion="4.1.0">
<id>UmbracoCms</id>
<version>8.0.0</version>
<title>Umbraco Cms</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>https://umbraco.com/dist/nuget/logo-small.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Installs Umbraco Cms in your Visual Studio ASP.NET project</description>
<summary>Installs Umbraco Cms in your Visual Studio ASP.NET project</summary>
<language>en-US</language>
<tags>umbraco</tags>
<repository type="git" url="https://github.com/umbraco/umbraco-cms" />
<dependencies>
<group targetFramework="net472">
<dependency id="UmbracoCms.Web" version="[$version$]" />
<!--
note: dependencies are specified as [x.y.z,x.999999) eg [2.1.0,2.999999) and NOT [2.1.0,3.0.0) because
the latter would pick anything below 3.0.0 and that includes prereleases such as 3.0.0-alpha, and we do
not want this to happen as the alpha of the next major is, really, the next major already.
-->
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.4.0, 2.999999)" />
<dependency id="ImageProcessor.Web" version="[4.12.1,4.999999)" />
<dependency id="ImageProcessor.Web.Config" version="[2.6.0,2.999999)" />
<dependency id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="[2.0.1,2.999999)" />
</group>
</dependencies>
</metadata>
<files>
<!-- files -->
<file src="$BuildTmp$\Configs\**" target="Content\Config" exclude="$BuildTmp$\Configs\Web.config.transform" />
<file src="$BuildTmp$\WebApp\Views\**" target="Content\Views" exclude="$BuildTmp$\WebApp\Views\Web.config" />
<file src="$BuildTmp$\WebApp\Global.asax" target="Content\Global.asax" />
<file src="$BuildTmp$\WebApp\config\BackOfficeTours\**" target="Content\Config\BackOfficeTours" />
<file src="$BuildTmp$\WebApp\Media\Web.config" target="Content\Media\Web.config" />
<!-- these files are copied by install.ps1 -->
<file src="$BuildTmp$\WebApp\Web.config" target="UmbracoFiles\Web.config" />
<file src="$BuildTmp$\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
<file src="$BuildTmp$\WebApp\config\splashes\**" target="UmbracoFiles\Config\splashes" />
<!-- tools -->
<!-- beware! install.ps1 not supported by PackageReference -->
<file src="tools\install.ps1" target="tools\install.ps1" />
<file src="tools\Readme.txt" target="tools\Readme.txt" />
<file src="tools\ReadmeUpgrade.txt" target="tools\ReadmeUpgrade.txt" />
<!-- config transforms -->
<!-- beware! config transforms not supported by PackageReference -->
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
<file src="tools\serilog.config.install.xdt" target="Content\config\serilog.config.install.xdt" />
<file src="tools\ClientDependency.config.install.xdt" target="Content\config\ClientDependency.config.install.xdt" />
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" /> <!-- FIXME: Content\ !! and then... transform?! -->
<!-- UmbracoCms props and targets -->
<file src="build\**" target="build" />
</files>
</package>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
AddUmbracoFilesToOutput;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
<CopyAllFilesToSingleFolderForMsdeployDependsOn>
AddUmbracoFilesToOutput;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForMsdeployDependsOn>
</PropertyGroup>
</Project>
+58
View File
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyUmbracoFilesToWebRootForDeploy" AfterTargets="CopyAllFilesToSingleFolderForMsdeploy">
<PropertyGroup>
<UmbracoFilesFolder>$(MSBuildThisFileDirectory)..\UmbracoFiles\</UmbracoFilesFolder>
</PropertyGroup>
<ItemGroup>
<UmbracoFiles Include="$(UmbracoFilesFolder)**\*" />
</ItemGroup>
<Copy SourceFiles="%(UmbracoFiles.FullPath)" DestinationFiles="$(_PackageTempDir)\%(RecursiveDir)%(Filename)%(Extension)" Condition="!Exists('%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
<Target Name="CopyUmbracoFilesToWebRoot" BeforeTargets="AfterBuild">
<!-- This copies the files listed in `AddUmbracoFilesToOutput` to the webroot during NuGet install and should -->
<!-- not be altered to support automated builds, use `CopyUmbracoFilesToWebRootForDeploy` for that instead -->
<PropertyGroup>
<UmbracoFilesFolder>$(MSBuildThisFileDirectory)..\UmbracoFiles\</UmbracoFilesFolder>
</PropertyGroup>
<ItemGroup>
<UmbracoFiles Include="$(UmbracoFilesFolder)**\*" />
</ItemGroup>
<Copy SourceFiles="%(UmbracoFiles.FullPath)" DestinationFiles="%(RecursiveDir)%(Filename)%(Extension)" Condition="!Exists('%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
<Target Name="AddUmbracoFilesToOutput">
<!-- With help from: http://blog.samstephens.co.nz/2010-10-18/msbuild-including-extra-files-multiple-builds/ -->
<ItemGroup>
<CustomFilesToInclude Include=".\App_Browsers\**\*">
<Dir>App_Browsers</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\App_Code\**\*">
<Dir>App_Code</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\App_Plugins\**\*">
<Dir>App_Plugins</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\bin\amd64\**\*">
<Dir>bin\amd64</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\bin\x86\**\*">
<Dir>bin\x86</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\Config\Splashes\**\*">
<Dir>Config\Splashes</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\data\**\*">
<Dir>data</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\umbraco\**\*">
<Dir>umbraco</Dir>
</CustomFilesToInclude>
<CustomFilesToInclude Include=".\Global.asax">
<Dir>.</Dir>
</CustomFilesToInclude>
<FilesForPackagingFromProject Include="@(CustomFilesToInclude)">
<DestinationRelativePath>%(CustomFilesToInclude.Dir)\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
</Project>
@@ -0,0 +1,8 @@
<?xml version="1.0"?>
<clientDependency xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<fileRegistration>
<providers>
<add name="CanvasProvider" xdt:Locator="Match(name)" xdt:Transform="Remove" />
</providers>
</fileRegistration>
</clientDependency>
+27
View File
@@ -0,0 +1,27 @@
888
888
888 888 88888b.d88b. 88888b. 888d888 8888b. .d8888b .d88b.
888 888 888 "888 "88b 888 "88b 888P" "88b d88P" d88""88b
888 888 888 888 888 888 888 888 .d888888 888 888 888
Y88 88Y 888 888 888 888 d88P 888 888 888 Y88b. Y88..88P
"Y888P" 888 888 888 88888P" 888 "Y888888 "Y8888P "Y88P"
------------------------------------------------------------------
Don't forget to build!
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
file (and config files in the config folder).
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
Publish this won't affect you.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, config\splashes and global.asax.
Please read the release notes on our.umbraco.com:
https://our.umbraco.com/download/releases
- Umbraco
+26
View File
@@ -0,0 +1,26 @@
888
888
888 888 88888b.d88b. 88888b. 888d888 8888b. .d8888b .d88b.
888 888 888 "888 "88b 888 "88b 888P" "88b d88P" d88""88b
888 888 888 888 888 888 888 888 .d888888 888 888 888
Y88 88Y 888 888 888 888 d88P 888 888 888 Y88b. Y88..88P
"Y888P" 888 888 888 88888P" 888 "Y888888 "Y8888P "Y88P"
------------------------------------------------------------------
Don't forget to build!
We've done our best to transform your configuration files but in case something is not quite right: we recommend you look in source control for the previous version so you can find the original files before they were transformed.
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
Publish this won't affect you.
The following items will now be automatically included when creating a deploy package or publishing to the file
system: umbraco, config\splashes and global.asax.
Please read the release notes on our.umbraco.com:
https://our.umbraco.com/contribute/releases
- Umbraco
@@ -0,0 +1,32 @@
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(name)" xdt:Transform="SetAttributes(type)">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(name)" xdt:Transform="SetAttributes(type)" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(name)" xdt:Transform="SetAttributes(type)" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(factoryType)" xdt:Transform="SetAttributes(factoryType)" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="Umbraco.Web.PublishedModels" xdt:Transform="InsertIfMissing" />
</namespaces>
</pages>
</system.web.webPages.razor>
<system.web>
<pages
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
xdt:Locator="Match(pageParserFilterType,pageBaseType,userControlBaseType)"
xdt:Transform="SetAttributes(pageParserFilterType,pageBaseType,userControlBaseType)">
<controls>
<add assembly="System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" xdt:Locator="Match(namespace)" xdt:Transform="SetAttributes(assembly)" />
</controls>
</pages>
</system.web>
</configuration>
+29
View File
@@ -0,0 +1,29 @@
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<runtime xdt:Transform="InsertIfMissing" />
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" xdt:Transform="InsertIfMissing" />
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Collections.Immutable')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Buffers')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Memory')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Numerics.Vectors')" xdt:Transform="Remove" />
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.5.0" newVersion="1.2.5.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" />
<bindingRedirect oldVersion="4.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" />
<bindingRedirect oldVersion="4.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="4.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
+209
View File
@@ -0,0 +1,209 @@
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<configSections xdt:Transform="InsertIfMissing" />
<configSections>
<sectionGroup name="applicationSettings" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<sectionGroup name="system.web.webPages.razor" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<sectionGroup name="umbracoConfiguration" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
<sectionGroup name="umbracoConfiguration" xdt:Locator="Match(name)">
<section name="settings" type="Umbraco.Core.Configuration.UmbracoSettings.UmbracoSettingsSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
<section name="dashBoard" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<section name="HealthChecks" type="Umbraco.Core.Configuration.HealthChecks.HealthChecksSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
</sectionGroup>
</configSections>
<appSettings xdt:Transform="InsertIfMissing" />
<appSettings>
<add key="owin:appStartup" value="UmbracoDefaultOwinStartup" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
<add key="Umbraco.ModelsBuilder.Enable" value="false" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
<add key="Umbraco.ModelsBuilder.ModelsMode" value="Nothing" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
</appSettings>
<umbracoConfiguration xdt:Transform="InsertIfMissing" />
<umbracoConfiguration>
<settings configSource="config\umbracoSettings.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
<dashBoard configSource="config\Dashboard.config" xdt:Locator="Match(configSource)" xdt:Transform="Remove" />
<HealthChecks configSource="config\HealthChecks.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
</umbracoConfiguration>
<system.data xdt:Transform="InsertIfMissing" />
<system.data>
<DbProviderFactories xdt:Transform="InsertIfMissing" />
<DbProviderFactories>
<remove invariant="System.Data.SqlServerCe.4.0" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe" xdt:Locator="Match(invariant)" xdt:Transform="SetAttributes(invariant,description,type)" />
</DbProviderFactories>
</system.data>
<clientDependency xdt:Transform="RemoveAttributes(version)" />
<system.web xdt:Transform="InsertIfMissing" />
<system.web>
<siteMap xdt:Transform="Remove" />
<httpRuntime xdt:Transform="InsertIfMissing" />
<httpRuntime maxRequestLength="51200" fcnMode="Single" xdt:Transform="SetAttributes(fcnMode,maxRequestLength)" />
<httpRuntime targetFramework="4.7.2" xdt:Locator="Condition(count(@targetFramework) != 1)" xdt:Transform="SetAttributes(targetFramework)" />
<membership defaultProvider="DefaultMembershipProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
<roleManager defaultProvider="DefaultRoleProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
<profile defaultProvider="DefaultProfileProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
<sessionState customProvider="DefaultSessionProvider" xdt:Locator="Match(customProvider)" xdt:Transform="Remove" />
<compilation xdt:Transform="InsertIfMissing" />
<xhtmlConformance xdt:Transform="Remove" />
<httpModules xdt:Transform="InsertIfMissing" />
<httpModules>
<add name="umbracoRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="umbracoBaseRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="viewstateMoverModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<!-- Don't remove the leading space below, this is to fix a quirk for a lot of releases where we added it with the space by default -->
<add name=" UmbracoModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule, Umbraco.Web" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
</httpModules>
<httpHandlers xdt:Transform="InsertIfMissing" />
<httpHandlers>
<add path="GoogleSpellChecker.ashx" xdt:Locator="Match(path)" xdt:Transform="Remove" />
</httpHandlers>
</system.web>
<system.webServer xdt:Transform="InsertIfMissing" />
<system.webServer>
<modules xdt:Transform="InsertIfMissing" />
<modules runAllManagedModulesForAllRequests="true" xdt:Transform="SetAttributes(runAllManagedModulesForAllRequests)" />
<modules>
<remove name="umbracoRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<remove name="viewstateMoverModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<remove name="umbracoBaseRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="umbracoRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="viewstateMoverModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="umbracoBaseRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<!-- Don't remove the leading space below, this is to fix a quirk for a lot of releases where we added it with the space by default -->
<add name=" UmbracoModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule, Umbraco.Web" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
</modules>
<staticContent xdt:Transform="InsertIfMissing" />
<staticContent>
<remove fileExtension=".svg" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
<remove fileExtension=".woff" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
<mimeMap fileExtension=".woff" mimeType="font/woff" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
<remove fileExtension=".woff2" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
<mimeMap fileExtension=".woff2" mimeType="font/woff2" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
<remove fileExtension=".less" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
<mimeMap fileExtension=".less" mimeType="text/css" xdt:Locator="Match(fileExtension)" xdt:Transform="InsertIfMissing" />
</staticContent>
<handlers>
<remove name="SpellChecker" xdt:Locator="Match(name)" xdt:Transform="Remove" />
<add name="SpellChecker" xdt:Locator="Match(name)" xdt:Transform="Remove" />
</handlers>
<security xdt:Transform="InsertIfMissing" />
<security>
<requestFiltering xdt:Transform="InsertIfMissing" />
<requestFiltering>
<requestLimits maxAllowedContentLength="52428800" xdt:Transform="InsertIfMissing" />
</requestFiltering>
</security>
</system.webServer>
<runtime xdt:Transform="InsertIfMissing" />
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" xdt:Transform="InsertIfMissing" />
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='HtmlAgilityPack')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='AutoMapper')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Newtonsoft.Json')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Mvc')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.WebPages.Razor')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Http')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security.OAuth')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security.Cookies')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http.Formatting')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.CodeAnalysis.CSharp')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='log4net')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Data.SqlServerCe')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.ValueTuple')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http.Formatting')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Collections.Immutable')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Buffers')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Memory')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Numerics.Vectors')" xdt:Transform="Remove" />
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.2.5.0" newVersion="1.2.5.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" />
<bindingRedirect oldVersion="4.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" />
<bindingRedirect oldVersion="4.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" />
<bindingRedirect oldVersion="4.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.web.webPages.razor xdt:Transform="Remove" />
<location path="umbraco" xdt:Locator="Match(path)" xdt:Transform="InsertIfMissing" />
<location path="umbraco" xdt:Locator="Match(path)">
<system.webServer xdt:Transform="InsertIfMissing" />
<system.webServer>
<urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" xdt:Transform="SetAttributes(doStaticCompression,doDynamicCompression,dynamicCompressionBeforeCache)" />
</system.webServer>
</location>
<location path="App_Plugins" xdt:Locator="Match(path)" xdt:Transform="InsertIfMissing" />
<location path="App_Plugins" xdt:Locator="Match(path)">
<system.webServer xdt:Transform="InsertIfMissing" />
<system.webServer>
<urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" xdt:Transform="SetAttributes(doStaticCompression,doDynamicCompression,dynamicCompressionBeforeCache)" />
</system.webServer>
</location>
</configuration>
@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<applications xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<add alias="content" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="media" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="settings" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="developer" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="users" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="member" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon)" />
<add alias="forms" name="Forms" sortOrder="6" xdt:Locator="Match(alias)" xdt:Transform="InsertIfMissing" />
<add alias="translation" sortOrder="7" xdt:Locator="Match(alias)" xdt:Transform="SetAttributes(icon,sortOrder)" />
</applications>
@@ -0,0 +1,6 @@
<?xml version="1.0"?>
<caching xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<caches>
<cache name="DiskCache" trimCache="false" xdt:Transform="SetAttributes(trimCache)" xdt:Locator="Match(name)" />
</caches>
</caching>
+107
View File
@@ -0,0 +1,107 @@
param($installPath, $toolsPath, $package, $project)
Write-Host "installPath:" "${installPath}"
Write-Host "toolsPath:" "${toolsPath}"
Write-Host " "
if ($project) {
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
# Create paths and list them
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
Write-Host "projectPath:" "${projectPath}"
$webConfigSource = Join-Path $projectPath "Web.config"
Write-Host "webConfigSource:" "${webConfigSource}"
$configFolder = Join-Path $projectPath "Config"
Write-Host "configFolder:" "${configFolder}"
# Copy umbraco and umbraco_files from package to project folder
$umbracoFolder = Join-Path $projectPath "Umbraco"
New-Item -ItemType Directory -Force -Path $umbracoFolder
$umbracoFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco"
Write-Host "copying files to $umbracoFolder ..."
# see https://support.microsoft.com/en-us/help/954404/return-codes-that-are-used-by-the-robocopy-utility-in-windows-server-2
robocopy $umbracoFolderSource $umbracoFolder /is /it /e
if (($lastexitcode -eq 1) -or ($lastexitcode -eq 3) -or ($lastexitcode -eq 5) -or ($lastexitcode -eq 7))
{
write-host "Copy succeeded!"
}
else
{
write-host "Copy failed with exit code:" $lastexitcode
}
$copyWebconfig = $true
$destinationWebConfig = Join-Path $projectPath "Web.config"
if(Test-Path $destinationWebConfig)
{
Try
{
[xml]$config = Get-Content $destinationWebConfig
$config.configuration.appSettings.ChildNodes | ForEach-Object {
if($_.key -eq "Umbraco.Core.ConfigurationStatus")
{
# The web.config has an umbraco-specific appSetting in it
# don't overwrite it and let config transforms do their thing
$copyWebconfig = $false
}
}
}
Catch
{
Write-Host "An error occurred:"
Write-Host $_
}
}
if($copyWebconfig -eq $true)
{
$packageWebConfigSource = Join-Path $installPath "UmbracoFiles\Web.config"
Copy-Item $packageWebConfigSource $destinationWebConfig -Force
# Copy files that don't get automatically copied for Website projects
# We do this here, when copyWebconfig is true because we only want to do it for new installs
# If this is an upgrade then the files should already be there
$splashesSource = Join-Path $installPath "UmbracoFiles\Config\splashes\*.*"
$splashesDestination = Join-Path $projectPath "Config\splashes\"
New-Item $splashesDestination -Type directory
Copy-Item $splashesSource $splashesDestination -Force
} else {
# This part only runs for upgrades
$upgradeViewSource = Join-Path $umbracoFolderSource "Views\install\*"
$upgradeView = Join-Path $umbracoFolder "Views\install\"
Write-Host "Copying2 ${upgradeViewSource} to ${upgradeView}"
Copy-Item $upgradeViewSource $upgradeView -Force
Try
{
# Disable tours for upgrades, presumably Umbraco experience is already available
$umbracoSettingsConfigPath = Join-Path $configFolder "umbracoSettings.config"
$content = (Get-Content $umbracoSettingsConfigPath).Replace('<tours enable="true">','<tours enable="false">')
# Saves with UTF-8 encoding without BOM which makes sure Umbraco can still read it
# Reference: https://stackoverflow.com/a/32951824/5018
[IO.File]::WriteAllLines($umbracoSettingsConfigPath, $content)
}
Catch
{
# Not a big problem if this fails, let it go
# Write-Host "An error occurred:"
# Write-Host $_
}
}
# Open appropriate readme
if($copyWebconfig -eq $true)
{
$DTE.ItemOperations.OpenFile($toolsPath + '\Readme.txt')
}
else
{
$DTE.ItemOperations.OpenFile($toolsPath + '\ReadmeUpgrade.txt')
}
}
@@ -0,0 +1 @@
<processing xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform" xdt:Transform="SetAttributes(preserveExifMetaData)" preserveExifMetaData="true" />
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">>
<appSettings>
<add key="serilog:using:File" value="Umbraco.Core" xdt:Transform="SetAttributes(value)" xdt:Locator="Match(key)"/>
<add key="serilog:write-to:File.shared" xdt:Transform="Remove" xdt:Locator="Match(key)"/>
</appSettings>
</configuration>
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<settings xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<content>
<EnableCanvasEditing xdt:Transform="Remove" />
</content>
<webservices xdt:Transform="Remove" />
<repositories xdt:Transform="Remove" />
</settings>
+52
View File
@@ -0,0 +1,52 @@
##############################################################
## V8 CMS - .NET & AngularJS Doc sites ##
## Built on demand only, NO automatic PR/branch triggers ##
## ##
## This build pipeline has a webhook for sucessful ##
## builds, that sends the ZIP artifacts to our.umb to host ##
##############################################################
# Name != name of pipeline but the build number format
# https://docs.microsoft.com/en-us/azure/devops/pipelines/process/run-number?view=azure-devops&tabs=yaml
# Build Pipeline triggers
# https://docs.microsoft.com/en-us/azure/devops/pipelines/repos/github?view=azure-devops&tabs=yaml#ci-triggers
trigger: none
pr: none
# Variables & their default values
variables:
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
# VM to run the build on & it's installed software
# https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops
# https://github.com/actions/virtual-environments/blob/master/images/win/Windows2019-Readme.md
pool:
vmImage: 'windows-2019'
jobs:
- job: buildDocs
displayName: 'Build static docs site as ZIPs'
steps:
- task: PowerShell@2
displayName: 'Prep build tool, build C# & JS Docs'
inputs:
targetType: 'inline'
script: |
$uenv=./build.ps1 -get -doc
$uenv.SandboxNode()
$uenv.CompileBelle()
$uenv.PrepareAngularDocs()
$nugetsourceUmbraco = "https://api.nuget.org/v3/index.json"
$uenv.PrepareCSharpDocs()
$uenv.RestoreNode()
errorActionPreference: 'continue'
workingDirectory: 'build'
- task: PublishPipelineArtifact@1
inputs:
targetPath: '$(Build.Repository.LocalPath)\build.out\'
artifact: 'docs'
publishLocation: 'pipeline'

Some files were not shown because too many files have changed in this diff Show More