Skip to content

feat: Support separate Articulate 6 and 7 package lanes (Umbraco 18 v…#479

Draft
gavinfaux wants to merge 8 commits into
Shazwazza:developfrom
gavinfaux:pr/umbraco18
Draft

feat: Support separate Articulate 6 and 7 package lanes (Umbraco 18 v…#479
gavinfaux wants to merge 8 commits into
Shazwazza:developfrom
gavinfaux:pr/umbraco18

Conversation

@gavinfaux
Copy link
Copy Markdown
Contributor

Summary

  • Adds explicit package lanes:
    • Articulate 6.x for Umbraco 16/17
    • Articulate 7.x for Umbraco 18
  • Updates build scripts and GitHub Actions to produce separate v6/v7 artifacts.
  • Updates Umbraco 18 OpenAPI/security registration to use public v18 APIs.
  • Adds local Docker lane wrappers for legacy and Umbraco 18 validation.
  • Clarifies Docker modes:
    • direct HTTP containers are boot/package smoke tests
    • Compose + Caddy is the full HTTPS backoffice path

Validation

  • net9 baseline tests passed
  • net10 baseline tests passed
  • Umbraco 18 net10 restore/build/test passed
  • Debug package lanes built locally
  • v18 Docker image built from lane package artifacts
  • v18 Compose HTTPS config/build validated

Remaining Risk

Full interactive login through the Caddy HTTPS backoffice path still needs a manual browser pass.

Decision needed on future Articulate version naming: we’re using v6 for the current Umbraco 16/17 line and proposing v7 for Umbraco 18, but with Umbraco 16 reaching EOL next month we could drop the v6 label and align Articulate major versions to Umbraco (e.g., Articulate 17 for Umbraco 17 and Articulate 18 for Umbraco 18).

gavinfaux added 8 commits May 14, 2026 21:37
…alidation and compatibility)

Enable an opt-in lane to validate against Umbraco 18 beta while preserving default Umbraco 16/17 lanes. Key changes:

- conditional code paths: add preprocessor guards to support both legacy (Umbraco 16/17) and v18 OpenAPI/Swagger APIs
- adapt URL providers/content finders and MasterModel constructors to match API surface changes.
- update ArticulateRouteValidatorTests and test mocks to avoid relying on obsolete Children property

The Umbraco 18 integration points are not binary-compatible with the Umbraco 16/17 package line, so the build now produces explicit package lanes:

  - Articulate 6 for Umbraco 16/17
  - Articulate 7 for Umbraco 18.

Docker validation also follows those lanes so local images restore the matching package artifact instead of accidentally mixing versions.

The local Docker flow keeps direct HTTP containers for fast boot smoke tests, but uses Compose plus Caddy for the real backoffice HTTPS path required by OpenIddict in production mode.

Constraint: Umbraco 18 OpenAPI/security APIs differ from the Umbraco 17 surface
Constraint: OpenIddict backoffice authorize requests require HTTPS in production mode
Rejected: Single NuGet package for 16/17/18 | compiled API surface is not binary-compatible

Directive: Do not mix package artifacts across lanes; build v6 and v7 packages separately

Tested: net9/net10 baseline tests; v18 net10 restore/build/test; Debug package builds for legacy and umbraco18; Docker v18 image build; Compose config and compose-build for v18 HTTPS lane

Not-tested: Full interactive Caddy HTTPS backoffice login after compose-up
…ncy versions

- Change CanAutoPublish guard from 'is not RuntimeLevel.Run' to
  'is RuntimeLevel.Boot or RuntimeLevel.BootFailed or RuntimeLevel.Unknown'
  so Umbraco 17's new RuntimeLevel.Upgrading does not block auto-publish
  after unattended install, without breaking Umbraco 16 where the enum
  value does not exist.
- Add diagnostic logging showing RuntimeLevel and AutoPublishOnStartup
  values to aid future debugging.
- Bump System.Security.Cryptography.Xml from [10.0.6,11.0.0) to
  [10.0.7,11.0.0) in Directory.Build.props, Directory.Packages.props,
  and src/Articulate/Articulate.csproj — required by Umbraco 18 beta2.
- Bump FileSignatures from 6.1.1 to 7.2.1 in both Articulate.csproj
  and Articulate.Web.csproj.
- Remove duplicate OpenMcdf references from test projects (already
  brought in transitively by Umbraco.Cms).
- Move central version ranges into Directory.Packages.props, keeping
  Directory.Build.props focused on per-TFM deltas only.
Umbraco 17+ auto-generates an HMAC secret key on first boot.  GetCropUrl()
returns URLs with &hmac=... — Razor HTML-encodes & to & in @ expressions.
Inside <style> blocks (raw text elements) the browser does NOT decode
&amp; back to &, so the server receives amp;width instead of width and
HMAC validation fails with 400.

Fix: add SecurityExtensions.ToCssStyleUrl() returning IHtmlContent.
Razor does not double-encode IHtmlContent, so & stays as & in the CSS output.
Replaces use of ToSafeCssUrl() + @ expression across six theme templates:

  - Material:   Master.cshtml, PostImageHeader.cshtml, AuthorInfo.cshtml
  - Mini:       Header.cshtml
  - Phantom:    Sidebar.cshtml
  - VAPOR:      List.cshtml

Also normalizes the URL input in ToSafeCssUrl() by escaping spaces and
URI characters before CSS escaping, preventing malformed CSS url()
values when the image URL contains spaces or percent-encoded characters.
…-site deps

Dockerfile:
- Accept DOTNET_SDK_IMAGE, DOTNET_ASPNET_IMAGE, TARGET_FRAMEWORK,
  UMBRACO_CMS_VERSION, PACKAGE_SOURCE, and PACKAGE_LANE as build args
  so a single Dockerfile produces images for Umbraco 16 (net9.0),
  17 (net10.0), and 18 (net10.0).
- Remove stale dotnet nuget locals all --clear (dead code — COPY layer
  invalidation already ensures a fresh NuGet cache).
- Add --no-restore to publish step to prevent a spurious second restore
  that could resolve the wrong TFM.
- Add early sanity check that nupkg files exist before attempting restore.
- Copy Directory.Packages.props into the build context.

docker-site:
- Make ArticulateDockerSite.csproj TargetFramework conditional so
  -p:TargetFramework=net9.0 overrides the default net10.0.
- Add explicit FileSignatures 7.2.1 and Markdig 1.2.0 package references
  to prevent NuGet downgrade warnings when Umbraco 18 resolves lower
  transitive versions.
- Wrap KnownIPNetworks.Clear() in #if NET10_0_OR_GREATER — the API
  does not exist on net9.0.
- Extend docker-test.ps1 to support umbraco16, umbraco17, umbraco18
  targets, each with its own port (16016/17017/18018), package lane,
  TFM, SDK image, and Umbraco version range.
- Add -Keep flag so containers stay running after the smoke test for
  manual browser inspection.
- Define target config in a  hash table — easy to add
  or tweak versions.
- Each target runs behind a Caddy sidecar for TLS termination (required
  by Umbraco Production mode).
- Update CI build.yml Docker note with the new build args, three-target
  matrix, and correct docker build examples.
- Add /build/test-site-publish to .gitignore.
DEVELOP.md:
- Replace outdated Docker section with the three-target matrix
  (umbraco16/17/18), correct ports, and -Keep flag.
- Document the repeatable build+test pipeline with package lanes.
- Add HMAC/CSS fix guidance explaining when to use ToCssStyleUrl().

build/docker-site/README.md:
- Move quick smoke test to the top as the recommended CI-like path.
- Add target/port/port table and build prerequisites.

docs/plans/articulate-docker-test-handoff.md:
- Replace stale debugging notes with current state summary, key
  changes, and known issues.

- alt scripts\docker-test.sh added
- Umbraco 18 lane is now aligned to the release-candidate package line.
- Build scripts fail fast if the  static web assets disappear from the packed NuGet.
- Local Docker validation stays script-owned through the  repo smoke-test scripts, while CI remains package-build only.
- The old compose wrappers and handoff notes were removed,  and the docs now describe the script-only workflow.
- Tested: v16/v17/v18 package build, PowerShell Docker smoke tests, bash Docker smoke tests, workflow YAML parse
Replace the local Windows path used for API compatibility checks with the `release/18.0` upstream branch reference.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant