diff --git a/.editorconfig b/.editorconfig index 4fa6b9f..95b414a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,139 +1,55 @@ root = true [*.cs] -# Formatting indent_style = space indent_size = 4 tab_width = 4 -end_of_line = crlf +end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true -# New lines -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 - -# Indentation -csharp_indent_case_contents = true -csharp_indent_switch_labels = true -csharp_indent_labels = flush_left - -# Spacing -csharp_space_after_cast = false -csharp_space_after_keywords_in_control_flow_statements = true -csharp_space_between_method_declaration_parameter_list_parentheses = false -csharp_space_between_method_call_parameter_list_parentheses = false -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_empty_parameter_list_parentheses = false -csharp_space_between_method_call_name_and_opening_parenthesis = false -csharp_space_between_method_call_empty_parameter_list_parentheses = false -csharp_space_after_comma = true -csharp_space_before_comma = false - -# Line preservation -csharp_preserve_single_line_statements = true -csharp_preserve_single_line_blocks = true - -# Naming Symbols +# Naming symbols dotnet_naming_symbols.public_properties.applicable_kinds = property dotnet_naming_symbols.public_properties.applicable_accessibilities = public - dotnet_naming_symbols.public_fields.applicable_kinds = field dotnet_naming_symbols.public_fields.applicable_accessibilities = public - dotnet_naming_symbols.private_fields.applicable_kinds = field dotnet_naming_symbols.private_fields.applicable_accessibilities = private - dotnet_naming_symbols.private_methods.applicable_kinds = method dotnet_naming_symbols.private_methods.applicable_accessibilities = private - dotnet_naming_symbols.constants.applicable_kinds = field dotnet_naming_symbols.constants.required_modifiers = const - dotnet_naming_symbols.local_variables.applicable_kinds = local -dotnet_naming_symbols.local_variables.applicable_accessibilities = local - dotnet_naming_symbols.parameters.applicable_kinds = parameter -dotnet_naming_symbols.parameters.applicable_accessibilities = * -# Naming Styles +# Naming styles dotnet_naming_style.pascal_case.capitalization = pascal_case - +dotnet_naming_style.camel_case.capitalization = camel_case dotnet_naming_style.camel_case_underscore.required_prefix = _ dotnet_naming_style.camel_case_underscore.capitalization = camel_case -dotnet_naming_style.camel_case.capitalization = camel_case - -dotnet_naming_style.constant_style.capitalization = pascal_case - -# Naming Rules +# Naming rules (warning: visible in CLI builds, not just the IDE) dotnet_naming_rule.public_props_must_be_pascal.symbols = public_properties dotnet_naming_rule.public_props_must_be_pascal.style = pascal_case -dotnet_naming_rule.public_props_must_be_pascal.severity = suggestion - +dotnet_naming_rule.public_props_must_be_pascal.severity = warning dotnet_naming_rule.public_fields_must_be_pascal.symbols = public_fields dotnet_naming_rule.public_fields_must_be_pascal.style = pascal_case -dotnet_naming_rule.public_fields_must_be_pascal.severity = suggestion - +dotnet_naming_rule.public_fields_must_be_pascal.severity = warning dotnet_naming_rule.private_fields_must_be_camel.symbols = private_fields dotnet_naming_rule.private_fields_must_be_camel.style = camel_case_underscore -dotnet_naming_rule.private_fields_must_be_camel.severity = suggestion - +dotnet_naming_rule.private_fields_must_be_camel.severity = warning dotnet_naming_rule.private_methods_must_be_pascal.symbols = private_methods dotnet_naming_rule.private_methods_must_be_pascal.style = pascal_case -dotnet_naming_rule.private_methods_must_be_pascal.severity = suggestion - -dotnet_naming_rule.constants_must_be_pascal_with_prefix.symbols = constants -dotnet_naming_rule.constants_must_be_pascal_with_prefix.style = constant_style -dotnet_naming_rule.constants_must_be_pascal_with_prefix.severity = suggestion - +dotnet_naming_rule.private_methods_must_be_pascal.severity = warning +dotnet_naming_rule.constants_must_be_pascal.symbols = constants +dotnet_naming_rule.constants_must_be_pascal.style = pascal_case +dotnet_naming_rule.constants_must_be_pascal.severity = warning dotnet_naming_rule.locals_must_be_camel.symbols = local_variables dotnet_naming_rule.locals_must_be_camel.style = camel_case -dotnet_naming_rule.locals_must_be_camel.severity = suggestion - +dotnet_naming_rule.locals_must_be_camel.severity = warning dotnet_naming_rule.parameters_must_be_camel.symbols = parameters dotnet_naming_rule.parameters_must_be_camel.style = camel_case -dotnet_naming_rule.parameters_must_be_camel.severity = suggestion - -# var preferences -csharp_style_var_for_built_in_types = true:suggestion -csharp_style_var_when_type_is_apparent = true:suggestion -csharp_style_var_elsewhere = true:suggestion - -# Expression-bodied members -csharp_style_expression_bodied_constructors = false:none -csharp_style_expression_bodied_operators = when_on_single_line:suggestion -csharp_style_expression_bodied_properties = when_on_single_line:suggestion -csharp_style_expression_bodied_indexers = when_on_single_line:suggestion -csharp_style_expression_bodied_accessors = when_on_single_line:suggestion -csharp_style_expression_bodied_lambdas = when_on_single_line:suggestion -csharp_style_expression_bodied_local_functions = when_on_single_line:suggestion -# csharp_style_expression_bodied_methods = when_on_single_line:suggestion - -# Pattern matching preferences -csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion -csharp_style_pattern_matching_over_as_with_null_check = true:suggestion -csharp_style_prefer_switch_expression = true:suggestion - -# Null checking preferences -dotnet_style_coalesce_expression = true:suggestion -dotnet_style_null_propagation = true:suggestion -dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion -csharp_style_conditional_delegate_call = true:suggestion +dotnet_naming_rule.parameters_must_be_camel.severity = warning -# Other preferences -csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion -csharp_style_inlined_variable_declaration = true:suggestion -csharp_style_throw_expression = true:suggestion -csharp_prefer_static_local_function = true:suggestion -csharp_style_prefer_index_operator = true:suggestion -csharp_style_prefer_range_operator = true:suggestion -dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion -dotnet_style_prefer_conditional_expression_over_return = true:suggestion +# CSharpier owns whitespace and layout +dotnet_diagnostic.IDE0055.severity = none diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..d001343 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,18 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + actions: + patterns: ["*"] + - package-ecosystem: nuget + directory: / + schedule: + interval: weekly + ignore: + # Date-versioned and tied to the PowerToys target; see CLAUDE.md (bump-deps skill) + - dependency-name: Microsoft.CommandPalette.Extensions + - dependency-name: Microsoft.WindowsAppSDK + - dependency-name: Microsoft.Windows.CsWinRT diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4341742 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,70 @@ +name: CI + +on: + push: + branches: [master] + pull_request: + branches: [master] + +permissions: + contents: read + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-test: + runs-on: windows-2022 + timeout-minutes: 30 + + steps: + # .editorconfig requires CRLF for .cs; match a Windows checkout so csharpier passes + - name: Use CRLF checkout + run: git config --global core.autocrlf true + + - name: Checkout + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + with: + fetch-depth: 0 + fetch-tags: true + + - name: Setup .NET SDK + uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5 + with: + dotnet-version: 10.0.x + cache: true + cache-dependency-path: | + **/Directory.Packages.props + **/*.csproj + + - name: Restore tools + run: dotnet tool restore + + - name: Check formatting + run: dotnet tool run csharpier check . + + - name: Build (Release, x64) + run: dotnet build UnityExtension/UnityExtension.csproj -c Release -p:Platform=x64 -p:SuppressSdkNoise=false + + # The unpackaged exe auto-initializes the Windows App SDK bootstrapper, which hangs the + # test host on runners without the Windows App Runtime; tests only need ProjectParser. + - name: Test + timeout-minutes: 10 + run: dotnet test UnityExtension.Tests/UnityExtension.Tests.csproj -c Release -p:Platform=x64 -p:WindowsAppSdkBootstrapInitialize=false --blame-hang --blame-hang-timeout 2m + + validate-version: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + + - name: Check csproj and manifest versions agree + run: | + v=$(grep -oP '(?<=)[^<]+' UnityExtension/UnityExtension.csproj | head -1) + a=$(grep -oP '(?<=)[^<]+' UnityExtension/UnityExtension.csproj | head -1) + f=$(grep -oP '(?<=)[^<]+' UnityExtension/UnityExtension.csproj | head -1) + m=$(grep -oP ']*\sVersion="\K[^"]+' UnityExtension/Package.appxmanifest | head -1) + echo "csproj=$v assembly=$a file=$f manifest=$m" + test "$a" = "$v.0" && test "$f" = "$v.0" && test "$m" = "$v.0" diff --git a/.github/workflows/release-msix.yml b/.github/workflows/release-msix.yml index 0f50f40..0f0f320 100644 --- a/.github/workflows/release-msix.yml +++ b/.github/workflows/release-msix.yml @@ -15,6 +15,7 @@ concurrency: jobs: build-sign-release: runs-on: windows-2022 + timeout-minutes: 45 defaults: run: @@ -27,13 +28,13 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: fetch-depth: 0 fetch-tags: true - name: Cache NuGet packages - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('**/Directory.Packages.props', '**/Directory.Build.props', '**/*.csproj', '**/nuget.config') }} @@ -41,7 +42,7 @@ jobs: ${{ runner.os }}-nuget- - name: Setup .NET SDK - uses: actions/setup-dotnet@v5 + uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5 with: dotnet-version: ${{ env.DOTNET_VERSION }} @@ -186,7 +187,7 @@ jobs: } - name: Upload workflow artifact - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: signed-msix path: | diff --git a/CLAUDE.md b/CLAUDE.md index 03fade8..e5466af 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -16,7 +16,7 @@ Store identity: `YidiMao.CommandPalette-Unity` (private values in git-ignored `d - `Directory.Packages.props` = all package versions; `dotnet-tools.json` = csharpier, minver-cli; `.pre-commit-config.yaml` = hooks - No Markdown under `UnityExtension/`; contributor guidance -> `CONTRIBUTING.md`; user docs -> `docs/` - Local-only (git-ignored, do not commit): `.claude/settings.local.json`, `docs/store-identity.md`, `scripts/` (`sign.ps1`, `pfx.ps1`, Unity path helpers) -- No test project exists; verify manually in PowerToys +- `UnityExtension.Tests/` (xunit) covers `ProjectParser` only; verify UI and commands manually in PowerToys - Gallery metadata lives in `microsoft/CmdPal-Extensions` (`extensions/maoyeedy/cmdpal-unity-extension/`), not in this repo ## Docs and tooling (use before answering from memory) @@ -47,19 +47,17 @@ dotnet build UnityExtension/UnityExtension.csproj -c Debug -p:Platform=x64 dotnet build UnityExtension/UnityExtension.csproj -c Release -p:Platform=x64 -p:SuppressSdkNoise=false # trim/AOT review ``` -- Debug CLI build is green (0 warnings, 0 errors) as of this refresh - CLI `Register` deploys need `-p:WindowsPackageType=MSIX`; MSIX bundle builds need `-p:GenerateAppxPackageOnBuild=true` (see `deploy` skill) - `IL2081` / `IL2104` from CsWinRT projections are known and non-fatal - After rebuild, reload Command Palette or restart PowerToys; test in the real host +- Build fails with MSB3021/MSB3027 "locked by: Unity Extension for Command Palette" = extension is running, not a code error. Compile-check with `-p:OutDir=/` and never kill it (see `docs/TROUBLESHOOTING.md`) ## Gotchas - `ProjectParser` swallows exceptions and may silently return an empty list -- Extension not loading: check manifest registration and CLSID first -- Breakpoints not hit: attach VS to the extension process, not the host shell -- `Microsoft.CommandPalette.Extensions` is date-versioned (currently 0.9.260303001); bump only for a newer PowerToys target -- `Microsoft.WindowsAppSDK` (2.2.0, matches PowerToys) and `Microsoft.Windows.CsWinRT` (2.2.0) must stay mutually compatible; keep <= PowerToys' pins -- Version sync: `Package.appxmanifest` Identity Version <-> `.csproj` ``/``/`` (currently 0.1.3 / 0.1.3.0); 4th segment `.0`. CI fails the tag build on mismatch +- `Microsoft.CommandPalette.Extensions` is date-versioned; bump only for a newer PowerToys target +- `Microsoft.WindowsAppSDK` and `Microsoft.Windows.CsWinRT` must stay mutually compatible; keep <= PowerToys' pins +- Version sync: `Package.appxmanifest` Identity Version <-> `.csproj` ``/``/``; 4th segment `.0`. CI fails the tag build on mismatch - Identity `Name`/`Publisher` must match Partner Center exactly - After identity/name changes delete `bin`, `obj`, `AppPackages` before rebuilding - Debug builds get `.Debug` package suffix and `(Dev)` display name; a release package blocks debug `-Register` (0x80073CFB), remove it first diff --git a/UnityExtension.sln.DotSettings b/UnityExtension.sln.DotSettings deleted file mode 100644 index f69224d..0000000 --- a/UnityExtension.sln.DotSettings +++ /dev/null @@ -1,5 +0,0 @@ - - DO_NOT_SHOW - DO_NOT_SHOW - DO_NOT_SHOW - DO_NOT_SHOW diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index 3422368..737e2cd 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -41,3 +41,9 @@ If an outdated-package check suggests a newer `Microsoft.WindowsAppSDK`, treat i If Release packaging fails with `WindowsPackageType=None` + `GenerateAppxPackageOnBuild=true`, remove hard `None` for build path. If packaging fails with `IL2104` / `NETSDK1144`, check trimming enabled for packaging build path, temporarily disable if needed. + +## Build fails: file is locked + +`MSB3021` / `MSB3027` "locked by: Unity Extension for Command Palette" means the extension is running inside Command Palette and holds `UnityExtension.exe`. It is not a code error. + +Close or unregister the extension (`winapp unregister`) for a normal build, or compile-check into another folder: `dotnet build UnityExtension/UnityExtension.csproj -c Debug -p:Platform=x64 -p:OutDir=/`. `-p:UseAppHost=false` fails with `NETSDK1067`.