├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── cd.yml │ └── ci.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Directory.Build.props ├── LICENSE ├── MyWPFApp.Package ├── Images │ ├── BadgeLogo.scale-100.png │ ├── BadgeLogo.scale-125.png │ ├── BadgeLogo.scale-150.png │ ├── BadgeLogo.scale-200.png │ ├── BadgeLogo.scale-400.png │ ├── LargeTile.scale-100.png │ ├── LargeTile.scale-125.png │ ├── LargeTile.scale-150.png │ ├── LargeTile.scale-200.png │ ├── LargeTile.scale-400.png │ ├── SmallTile.scale-100.png │ ├── SmallTile.scale-125.png │ ├── SmallTile.scale-150.png │ ├── SmallTile.scale-200.png │ ├── SmallTile.scale-400.png │ ├── SplashScreen.scale-100.png │ ├── SplashScreen.scale-125.png │ ├── SplashScreen.scale-150.png │ ├── SplashScreen.scale-200.png │ ├── SplashScreen.scale-400.png │ ├── Square150x150Logo.png │ ├── Square150x150Logo.scale-100.png │ ├── Square150x150Logo.scale-125.png │ ├── Square150x150Logo.scale-150.png │ ├── Square150x150Logo.scale-200.png │ ├── Square150x150Logo.scale-400.png │ ├── Square44x44Logo.altform-unplated_targetsize-16.png │ ├── Square44x44Logo.altform-unplated_targetsize-24.png │ ├── Square44x44Logo.altform-unplated_targetsize-256.png │ ├── Square44x44Logo.altform-unplated_targetsize-32.png │ ├── Square44x44Logo.altform-unplated_targetsize-48.png │ ├── Square44x44Logo.scale-100.png │ ├── Square44x44Logo.scale-125.png │ ├── Square44x44Logo.scale-150.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.scale-400.png │ ├── Square44x44Logo.targetsize-16.png │ ├── Square44x44Logo.targetsize-24.png │ ├── Square44x44Logo.targetsize-256.png │ ├── Square44x44Logo.targetsize-32.png │ ├── Square44x44Logo.targetsize-48.png │ ├── StoreLogo.backup.png │ ├── StoreLogo.scale-100.png │ ├── StoreLogo.scale-125.png │ ├── StoreLogo.scale-150.png │ ├── StoreLogo.scale-200.png │ ├── StoreLogo.scale-400.png │ ├── WideTile.scale-100.png │ ├── WideTile.scale-125.png │ ├── WideTile.scale-150.png │ ├── WideTile.scale-200.png │ └── WideTile.scale-400.png ├── MyWPFApp.Package.wapproj ├── Package.appinstaller └── Package.appxmanifest ├── MyWPFApp.sln ├── MyWPFApp ├── App.xaml ├── App.xaml.cs ├── ApplicationInsights.config ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── MyWPFApp.csproj ├── Properties │ └── PublishProfiles │ │ ├── SelfContainedWin64.pubxml │ │ ├── SelfContainedWin64Debug.pubxml │ │ ├── SelfContainedWin86.pubxml │ │ └── SelfContainedWin86Debug.pubxml ├── Telemetry │ ├── AppVersionTelemetryInitializer.cs │ ├── DiagnosticsClient.cs │ └── EnvironmentTelemetryInitializer.cs ├── ThisAppInfo.cs └── win.ico ├── MyWpfApp.Tests ├── MyWPFApp.Tests.csproj └── ThisAppInfoTest.cs ├── README.md ├── SECURITY.md ├── doc └── images │ ├── editToCustomizeSettings.png │ ├── findArtifact.png │ ├── myWpfApp.Package.Properties.png │ ├── pickAPublishTarget.png │ ├── profileSettings.png │ ├── publishProfileComplete.png │ ├── releaseAssetLocation.png │ ├── releases.png │ ├── renameProfile.png │ └── versionEnvironmentVariables.png └── version.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome:http://EditorConfig.org 2 | # From https://raw.githubusercontent.com/dotnet/roslyn/master/.editorconfig 3 | 4 | # top-most EditorConfig file 5 | root = true 6 | 7 | # Don't use tabs for indentation. 8 | [*] 9 | indent_style = space 10 | trim_trailing_whitespace = true 11 | # (Please don't specify an indent_size here; that has too many unintended consequences.) 12 | 13 | # Code files 14 | [*.{cs,csx,vb,vbx}] 15 | indent_size = 4 16 | insert_final_newline = true 17 | charset = utf-8-bom 18 | 19 | # Xml project files 20 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] 21 | indent_size = 2 22 | 23 | # Xml config files 24 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] 25 | indent_size = 2 26 | 27 | # Yml/Yaml files 28 | [*.{yaml,yml}] 29 | indent_size = 2 30 | 31 | # Powershell files 32 | [*.ps1] 33 | indent_size = 2 34 | 35 | # JSON files 36 | [*.json] 37 | indent_size = 2 38 | 39 | # Shell scripts 40 | [*.sh] 41 | end_of_line = lf 42 | 43 | [*.{cmd,bat}] 44 | end_of_line = crlf 45 | 46 | # Dotnet code style settings: 47 | [*.{cs,vb}] 48 | # Sort using and Import directives with System.* appearing first 49 | dotnet_sort_system_directives_first = true 50 | # Put a blank line between System.* and Microsoft.* 51 | dotnet_separate_import_directive_groups = true 52 | 53 | # Avoid "this." and "Me." if not necessary 54 | dotnet_style_qualification_for_field = false:suggestion 55 | dotnet_style_qualification_for_property = false:suggestion 56 | dotnet_style_qualification_for_method = false:suggestion 57 | dotnet_style_qualification_for_event = false:suggestion 58 | 59 | # Use language keywords instead of framework type names for type references 60 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 61 | dotnet_style_predefined_type_for_member_access = true:suggestion 62 | 63 | # Prefer read-only on fields 64 | dotnet_style_readonly_field = true:warning 65 | 66 | # Suggest more modern language features when available 67 | dotnet_style_object_initializer = true:suggestion 68 | dotnet_style_collection_initializer = true:suggestion 69 | dotnet_style_coalesce_expression = true:suggestion 70 | dotnet_style_null_propagation = true:suggestion 71 | dotnet_style_explicit_tuple_names = true:suggestion 72 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 73 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 74 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 75 | dotnet_style_prefer_conditional_expression_over_return = false 76 | dotnet_style_prefer_conditional_expression_over_assignment = false 77 | dotnet_style_prefer_auto_properties = true:suggestion 78 | 79 | # Parentheses 80 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 81 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 82 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 83 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 84 | 85 | # Accessibility modifiers 86 | dotnet_style_require_accessibility_modifiers = always:suggestion 87 | 88 | 89 | # Naming Rules 90 | 91 | # Interfaces start with an I and are PascalCased 92 | dotnet_naming_rule.interfaces_must_be_pascal_cased_and_prefixed_with_I.symbols = interface_symbols 93 | dotnet_naming_rule.interfaces_must_be_pascal_cased_and_prefixed_with_I.style = pascal_case_and_prefix_with_I_style 94 | dotnet_naming_rule.interfaces_must_be_pascal_cased_and_prefixed_with_I.severity = warning 95 | 96 | # External members are PascalCased 97 | dotnet_naming_rule.externally_visible_members_must_be_pascal_cased.symbols = externally_visible_symbols 98 | dotnet_naming_rule.externally_visible_members_must_be_pascal_cased.style = pascal_case_style 99 | dotnet_naming_rule.externally_visible_members_must_be_pascal_cased.severity = warning 100 | 101 | # Parameters are camelCased 102 | dotnet_naming_rule.parameters_must_be_camel_cased.symbols = parameter_symbols 103 | dotnet_naming_rule.parameters_must_be_camel_cased.style = camel_case_style 104 | dotnet_naming_rule.parameters_must_be_camel_cased.severity = warning 105 | 106 | # Constants are PascalCased 107 | dotnet_naming_rule.constants_must_be_pascal_cased.symbols = constant_symbols 108 | dotnet_naming_rule.constants_must_be_pascal_cased.style = pascal_case_style 109 | dotnet_naming_rule.constants_must_be_pascal_cased.severity = warning 110 | 111 | # Uncomment this group and comment out the next group if you prefer s_ prefixes for static fields 112 | 113 | # Private static fields are prefixed with s_ and are camelCased like s_myStatic 114 | #dotnet_naming_rule.private_static_fields_must_be_camel_cased_and_prefixed_with_s_underscore.symbols = private_static_field_symbols 115 | #dotnet_naming_rule.private_static_fields_must_be_camel_cased_and_prefixed_with_s_underscore.style = camel_case_and_prefix_with_s_underscore_style 116 | #dotnet_naming_rule.private_static_fields_must_be_camel_cased_and_prefixed_with_s_underscore.severity = warning 117 | 118 | # Static readonly fields are PascalCased 119 | dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.symbols = private_static_readonly_field_symbols 120 | dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.style = pascal_case_style 121 | dotnet_naming_rule.static_readonly_fields_should_be_pascal_case.severity = warning 122 | 123 | # Comment this group and uncomment out the next group if you don't want _ prefixed fields. 124 | 125 | # Private instance fields are camelCased with an _ like _myField 126 | dotnet_naming_rule.private_instance_fields_must_be_camel_cased_and_prefixed_with_underscore.symbols = private_field_symbols 127 | dotnet_naming_rule.private_instance_fields_must_be_camel_cased_and_prefixed_with_underscore.style = camel_case_and_prefix_with_underscore_style 128 | dotnet_naming_rule.private_instance_fields_must_be_camel_cased_and_prefixed_with_underscore.severity = warning 129 | 130 | # Private instance fields are camelCased 131 | #dotnet_naming_rule.private_instance_fields_must_be_camel_cased.symbols = private_field_symbols 132 | #dotnet_naming_rule.private_instance_fields_must_be_camel_cased.style = camel_case_style 133 | #dotnet_naming_rule.private_instance_fields_must_be_camel_cased.severity = warning 134 | 135 | # Symbols 136 | dotnet_naming_symbols.externally_visible_symbols.applicable_kinds = class,struct,interface,enum,property,method,field,event,delegate 137 | dotnet_naming_symbols.externally_visible_symbols.applicable_accessibilities = public,internal,friend,protected,protected_internal,protected_friend,private_protected 138 | 139 | dotnet_naming_symbols.interface_symbols.applicable_kinds = interface 140 | dotnet_naming_symbols.interface_symbols.applicable_accessibilities = * 141 | 142 | dotnet_naming_symbols.parameter_symbols.applicable_kinds = parameter 143 | dotnet_naming_symbols.parameter_symbols.applicable_accessibilities = * 144 | 145 | dotnet_naming_symbols.constant_symbols.applicable_kinds = field 146 | dotnet_naming_symbols.constant_symbols.required_modifiers = const 147 | dotnet_naming_symbols.constant_symbols.applicable_accessibilities = * 148 | 149 | dotnet_naming_symbols.private_static_field_symbols.applicable_kinds = field 150 | dotnet_naming_symbols.private_static_field_symbols.required_modifiers = static,shared 151 | dotnet_naming_symbols.private_static_field_symbols.applicable_accessibilities = private 152 | 153 | dotnet_naming_symbols.private_static_readonly_field_symbols.applicable_kinds = field 154 | dotnet_naming_symbols.private_static_readonly_field_symbols.required_modifiers = static,shared,readonly 155 | dotnet_naming_symbols.private_static_readonly_field_symbols.applicable_accessibilities = private 156 | 157 | dotnet_naming_symbols.private_field_symbols.applicable_kinds = field 158 | dotnet_naming_symbols.private_field_symbols.applicable_accessibilities = private 159 | 160 | # Styles 161 | dotnet_naming_style.camel_case_style.capitalization = camel_case 162 | 163 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 164 | 165 | dotnet_naming_style.camel_case_and_prefix_with_s_underscore_style.required_prefix = s_ 166 | dotnet_naming_style.camel_case_and_prefix_with_s_underscore_style.capitalization = camel_case 167 | 168 | dotnet_naming_style.camel_case_and_prefix_with_underscore_style.required_prefix = _ 169 | dotnet_naming_style.camel_case_and_prefix_with_underscore_style.capitalization = camel_case 170 | 171 | dotnet_naming_style.pascal_case_and_prefix_with_I_style.required_prefix = I 172 | dotnet_naming_style.pascal_case_and_prefix_with_I_style.capitalization = pascal_case 173 | 174 | 175 | # CSharp code style settings: 176 | [*.cs] 177 | # Modifier order 178 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion 179 | 180 | # Code block 181 | csharp_prefer_braces = false:none 182 | 183 | # Indentation preferences 184 | csharp_indent_block_contents = true 185 | csharp_indent_braces = false 186 | csharp_indent_case_contents = true 187 | csharp_indent_switch_labels = true 188 | csharp_indent_labels = flush_left 189 | 190 | # Prefer "var" everywhere 191 | csharp_style_var_for_built_in_types = true:suggestion 192 | csharp_style_var_when_type_is_apparent = true:suggestion 193 | csharp_style_var_elsewhere = true:suggestion 194 | 195 | # Code style defaults 196 | csharp_preserve_single_line_blocks = true 197 | csharp_preserve_single_line_statements = true 198 | 199 | # Prefer method-like constructs to have a block body 200 | csharp_style_expression_bodied_methods = false:none 201 | csharp_style_expression_bodied_constructors = false:none 202 | csharp_style_expression_bodied_operators = false:none 203 | 204 | # Prefer property-like constructs to have an expression-body 205 | csharp_style_expression_bodied_properties = true:none 206 | csharp_style_expression_bodied_indexers = true:none 207 | csharp_style_expression_bodied_accessors = true:none 208 | 209 | # Expression 210 | csharp_prefer_simple_default_expression = true:suggestion 211 | csharp_style_deconstructed_variable_declaration = true:suggestion 212 | csharp_style_pattern_local_over_anonymous_function = true:suggestion 213 | 214 | # Pattern matching 215 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 216 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 217 | csharp_style_inlined_variable_declaration = true:suggestion 218 | 219 | # Null checking preferences 220 | csharp_style_throw_expression = true:suggestion 221 | csharp_style_conditional_delegate_call = true:suggestion 222 | 223 | # Newline settings 224 | csharp_new_line_before_open_brace = all 225 | csharp_new_line_before_else = true 226 | csharp_new_line_before_catch = true 227 | csharp_new_line_before_finally = true 228 | csharp_new_line_before_members_in_object_initializers = true 229 | csharp_new_line_before_members_in_anonymous_types = true 230 | csharp_new_line_between_query_expression_clauses = true 231 | 232 | # Space preferences 233 | csharp_space_after_cast = false 234 | csharp_space_after_colon_in_inheritance_clause = true 235 | csharp_space_after_comma = true 236 | csharp_space_after_dot = false 237 | csharp_space_after_keywords_in_control_flow_statements = true 238 | csharp_space_after_semicolon_in_for_statement = true 239 | csharp_space_around_binary_operators = before_and_after 240 | csharp_space_around_declaration_statements = do_not_ignore 241 | csharp_space_before_colon_in_inheritance_clause = true 242 | csharp_space_before_comma = false 243 | csharp_space_before_dot = false 244 | csharp_space_before_open_square_brackets = false 245 | csharp_space_before_semicolon_in_for_statement = false 246 | csharp_space_between_empty_square_brackets = false 247 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 248 | csharp_space_between_method_call_name_and_opening_parenthesis = false 249 | csharp_space_between_method_call_parameter_list_parentheses = false 250 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 251 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 252 | csharp_space_between_method_declaration_parameter_list_parentheses = false 253 | csharp_space_between_parentheses = false 254 | csharp_space_between_square_brackets = false -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.github/workflows/cd.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. 2 | # Licensed under the MIT license. 3 | 4 | # This continuous delivery pipeline is meant to be triggered on release, anytime a user pushes code associated to a git tag, 5 | # and will run against multiple configurations and production environments. 6 | # This pipeline builds the Wpf project based upon the configuration matrix below. In order to 7 | # create different channels of the application, the pipeline uses the Package.Identity.Name defined in the 8 | # Package.appxmanifest in the Windows Application Packaging Project to uniquely identify the application, 9 | # depending on which channel is being built. 10 | # Once the MSIX is created for each channel configuration, the agent archives the AppPackages folder, then creates 11 | # a Release with the specified git release tag. The archive is uploaded to the release as an asset for storage or distribution. 12 | name: Wpf Continuous Delivery 13 | 14 | # Trigger on any push with a git tag 15 | # To create a git tag, run the following commands on the branch you wish to release: 16 | # git tag 1.0.0.0 17 | # git push origin --tags 18 | on: 19 | push: 20 | tags: 21 | - '*' 22 | 23 | jobs: 24 | 25 | build: 26 | 27 | strategy: 28 | 29 | # The following build matrix allows builds across multiple configurations (Debug and Release) and production environments such as 30 | # development, production for sideload applications and production for the Microsoft store. 31 | # For more information, see https://help.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow#configuring-a-build-matrix 32 | matrix: 33 | channel: [Dev, Prod_Sideload, Prod_Store] 34 | targetPlatform: [x86, x64] 35 | include: 36 | 37 | # includes the following variables for the matrix leg matching Dev 38 | - channel: Dev 39 | ChannelName: Dev 40 | Configuration: Debug 41 | DistributionUrl: https://microsoft.github.io/github-actions-for-desktop-apps-distribution-dev 42 | MsixPackageId: MyWPFApp.DevOpsDemo.Dev 43 | MsixPublisherId: CN=GitHubActionsDemo 44 | MsixPackageDisplayName: MyWPFApp (Dev) 45 | 46 | # includes the following variables for the matrix leg matching Prod_Sideload 47 | - channel: Prod_Sideload 48 | Configuration: Release 49 | ChannelName: Prod_Sideload 50 | DistributionUrl: https://microsoft.github.io/github-actions-for-desktop-apps-distribution-prod 51 | MsixPackageId: MyWPFApp.DevOpsDemo.ProdSideload 52 | MsixPublisherId: CN=GitHubActionsDemo 53 | MsixPackageDisplayName: MyWPFApp (ProdSideload) 54 | 55 | # includes the following variables for the matrix leg matching Prod_Store 56 | - channel: Prod_Store 57 | Configuration: Release 58 | ChannelName: Prod_Store 59 | DistributionUrl: 60 | MsixPackageId: MyWPFApp.DevOpsDemo.ProdStore 61 | MsixPublisherId: CN=GitHubActionsDemo 62 | MsixPackageDisplayName: MyWPFApp (ProdStore) 63 | 64 | runs-on: windows-latest 65 | 66 | env: 67 | App_Packages_Archive: AppPackages.zip 68 | App_Packages_Directory: AppPackages 69 | SigningCertificate: GitHubActionsDemo.pfx 70 | Solution_Path: MyWpfApp.sln 71 | Test_Project_Path: MyWpfApp.Tests\MyWpfApp.Tests.csproj 72 | Wpf_Project_Path: MyWpfApp\MyWpfApp.csproj 73 | Wap_Project_Directory: MyWpfApp.Package 74 | Wap_Project_Name: MyWpfApp.Package.wapproj 75 | Actions_Allow_Unsecure_Commands: true # Allows AddPAth and SetEnv commands 76 | 77 | steps: 78 | - name: Checkout 79 | uses: actions/checkout@v2 80 | with: 81 | fetch-depth: 0 # avoid shallow clone so nbgv can do its work. 82 | 83 | # Use Nerdbank.GitVersioning to set version variables: https://github.com/AArnott/nbgv 84 | - name: Use Nerdbank.GitVersioning to set version variables 85 | uses: dotnet/nbgv@master 86 | id: nbgv 87 | 88 | # Install the .NET Core workload 89 | - name: Install .NET Core 90 | uses: actions/setup-dotnet@v3 91 | with: 92 | dotnet-version: '6.0.x' 93 | 94 | # Add MsBuild to the PATH: https://github.com/microsoft/setup-msbuild 95 | - name: Setup MSBuild.exe 96 | uses: microsoft/setup-msbuild@v1.1 97 | 98 | # Update the appxmanifest before build by setting the per-channel values set in the matrix such as 99 | # the Package.Identity.Version or the Package.Identity.Name, which allows multiple channels to be built. 100 | - name: Update manifest version 101 | run: | 102 | [xml]$manifest = get-content ".\$env:Wap_Project_Directory\Package.appxmanifest" 103 | $manifest.Package.Identity.Version = "${{ steps.nbgv.outputs.SimpleVersion }}.0" 104 | $manifest.Package.Identity.Name = "${{ matrix.MsixPackageId }}" 105 | $manifest.Package.Identity.Publisher = "${{ matrix.MsixPublisherId }}" 106 | $manifest.Package.Properties.DisplayName = "${{ matrix.MsixPackageDisplayName }}" 107 | $manifest.Package.Applications.Application.VisualElements.DisplayName = "${{ matrix.MsixPackageDisplayName }}" 108 | $manifest.save(".\$env:Wap_Project_Directory\Package.appxmanifest") 109 | 110 | # Decode the Base64 encoded Pfx 111 | - name: Decode the Pfx 112 | run: | 113 | $pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.Base64_Encoded_Pfx }}") 114 | $currentDirectory = Get-Location 115 | $certificatePath = Join-Path -Path $currentDirectory -ChildPath $env:Wap_Project_Directory -AdditionalChildPath $env:SigningCertificate 116 | [IO.File]::WriteAllBytes("$certificatePath", $pfx_cert_byte) 117 | if: matrix.ChannelName != 'Prod_Store' 118 | 119 | # Restore the application 120 | - name: Restore the Wpf application to populate the obj folder 121 | run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier 122 | env: 123 | Configuration: ${{ matrix.Configuration }} 124 | RuntimeIdentifier: win-${{ matrix.targetplatform }} 125 | 126 | # Build the Windows Application Packaging project for Dev and Prod_Sideload 127 | - name: Build the Windows Application Packaging Project (wapproj) for ${{ matrix.ChannelName }} 128 | run: msbuild $env:Solution_Path /p:Platform=$env:TargetPlatform /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:BuildMode /p:AppxBundle=$env:AppxBundle /p:PackageCertificateKeyFile=$env:SigningCertificate /p:PackageCertificatePassword=${{ secrets.Pfx_Key }} 129 | if: matrix.ChannelName != 'Prod_Store' 130 | env: 131 | AppxBundle: Never 132 | AppInstallerUri: ${{ matrix.DistributionUrl }} 133 | BuildMode: SideloadOnly 134 | Configuration: ${{ matrix.Configuration }} 135 | GenerateAppInstallerFile: True 136 | TargetPlatform: ${{ matrix.targetplatform }} 137 | 138 | # Build the Windows Application Packaging project for Prod_Store 139 | - name: Build the Windows Application Packaging Project (wapproj) for ${{ matrix.ChannelName }} 140 | run: msbuild $env:Solution_Path /p:Platform=$env:TargetPlatform /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:BuildMode /p:AppxBundle=$env:AppxBundle /p:GenerateAppInstallerFile=$env:GenerateAppInstallerFile /p:AppxPackageSigningEnabled=$env:AppxPackageSigningEnabled 141 | if: matrix.ChannelName == 'Prod_Store' 142 | env: 143 | AppxBundle: Never 144 | AppxPackageSigningEnabled: False 145 | BuildMode: StoreUpload 146 | Configuration: ${{ matrix.Configuration }} 147 | GenerateAppInstallerFile: False 148 | TargetPlatform: ${{ matrix.targetplatform }} 149 | 150 | # Remove the .pfx 151 | - name: Remove the .pfx 152 | run: Remove-Item -path $env:Wap_Project_Directory\$env:SigningCertificate 153 | if: matrix.ChannelName != 'Prod_Store' 154 | 155 | # Archive the package 156 | - name: Create archive 157 | run: Compress-Archive -Path $env:Wap_Project_Directory\$env:App_Packages_Directory\* -DestinationPath $env:Wap_Project_Directory\$env:App_Packages_Directory\$env:App_Packages_Archive 158 | 159 | # Create the release: https://github.com/actions/create-release 160 | - name: Create release 161 | id: create_release 162 | uses: actions/create-release@v1 163 | env: 164 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token 165 | with: 166 | tag_name: ${{ github.ref}}.${{matrix.ChannelName}}.${{ matrix.targetplatform }} 167 | release_name: ${{ github.ref }}.${{ matrix.ChannelName }}.${{ matrix.targetplatform }} 168 | draft: false 169 | prerelease: false 170 | 171 | # Upload release asset: https://github.com/actions/upload-release-asset 172 | - name: Update release asset 173 | id: upload-release-asset 174 | uses: actions/upload-release-asset@v1 175 | env: 176 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 177 | with: 178 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 179 | asset_path: ${{ env.Wap_Project_Directory }}\${{ env.App_Packages_Directory }}\${{ env.App_Packages_Archive }} 180 | asset_name: ${{ env.App_Packages_Archive }} 181 | asset_content_type: application/zip 182 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) Microsoft Corporation. 2 | # Licensed under the MIT license. 3 | 4 | # This continuous integration pipeline is triggered anytime a user pushes code to the repo. 5 | # This pipeline builds the Wpf project, runs unit tests, then saves the MSIX build artifact. 6 | name: Wpf Continuous Integration 7 | 8 | # Trigger on every master branch push and pull request 9 | on: 10 | push: 11 | branches: 12 | - master 13 | - 'maintenence/*' 14 | pull_request: 15 | branches: 16 | - master 17 | 18 | jobs: 19 | 20 | build: 21 | 22 | strategy: 23 | matrix: 24 | targetplatform: [x86, x64] 25 | 26 | runs-on: windows-latest 27 | 28 | env: 29 | App_Packages_Directory: AppPackages 30 | SigningCertificate: GitHubActionsDemo.pfx 31 | Solution_Path: MyWpfApp.sln 32 | Test_Project_Path: MyWpfApp.Tests\MyWpfApp.Tests.csproj 33 | Wpf_Project_Path: MyWpfApp\MyWpfApp.csproj 34 | Wap_Project_Directory: MyWpfApp.Package 35 | Wap_Project_Name: MyWpfApp.Package.wapproj 36 | Actions_Allow_Unsecure_Commands: true # Allows AddPAth and SetEnv commands 37 | 38 | steps: 39 | - name: Checkout 40 | uses: actions/checkout@v2 41 | with: 42 | fetch-depth: 0 # avoid shallow clone so nbgv can do its work. 43 | 44 | # Use Nerdbank.GitVersioning to set version variables: https://github.com/AArnott/nbgv 45 | - name: Use Nerdbank.GitVersioning to set version variables 46 | uses: dotnet/nbgv@master 47 | id: nbgv 48 | 49 | # Install the .NET Core workload 50 | - name: Install .NET Core 51 | uses: actions/setup-dotnet@v3 52 | with: 53 | dotnet-version: '6.0.x' 54 | 55 | # Add MsBuild to the PATH: https://github.com/microsoft/setup-msbuild 56 | - name: Setup MSBuild.exe 57 | uses: microsoft/setup-msbuild@v1.1 58 | 59 | # Update the version before build 60 | - name: Update manifest version 61 | run: | 62 | [xml]$manifest = get-content ".\$env:Wap_Project_Directory\Package.appxmanifest" 63 | $manifest.Package.Identity.Version = "${{ steps.nbgv.outputs.SimpleVersion }}.0" 64 | $manifest.save(".\$env:Wap_Project_Directory\Package.appxmanifest") 65 | 66 | # Test 67 | - name: Execute Unit Tests 68 | run: dotnet test $env:Test_Project_Path 69 | 70 | # Restore the application 71 | - name: Restore the Wpf application to populate the obj folder 72 | run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier 73 | env: 74 | Configuration: Debug 75 | RuntimeIdentifier: win-${{ matrix.targetplatform }} 76 | 77 | # Decode the Base64 encoded Pfx 78 | - name: Decode the Pfx 79 | run: | 80 | $pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.Base64_Encoded_Pfx }}") 81 | $currentDirectory = Get-Location 82 | $certificatePath = Join-Path -Path $currentDirectory -ChildPath $env:Wap_Project_Directory -AdditionalChildPath $env:SigningCertificate 83 | [IO.File]::WriteAllBytes("$certificatePath", $pfx_cert_byte) 84 | 85 | # Build the Windows Application Packaging project 86 | - name: Build the Windows Application Packaging Project (wapproj) 87 | run: msbuild $env:Solution_Path /p:Platform=$env:TargetPlatform /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:BuildMode /p:AppxBundle=$env:AppxBundle /p:PackageCertificateKeyFile=$env:SigningCertificate /p:PackageCertificatePassword=${{ secrets.Pfx_Key }} 88 | env: 89 | AppxBundle: Never 90 | BuildMode: SideloadOnly 91 | Configuration: Debug 92 | TargetPlatform: ${{ matrix.targetplatform }} 93 | 94 | # Remove the .pfx 95 | - name: Remove the .pfx 96 | run: Remove-Item -path $env:Wap_Project_Directory\$env:SigningCertificate 97 | 98 | # Upload the MSIX package: https://github.com/marketplace/actions/upload-artifact 99 | - name: Upload build artifacts 100 | uses: actions/upload-artifact@v1 101 | with: 102 | name: MSIX Package 103 | path: ${{ env.Wap_Project_Directory }}\${{ env.App_Packages_Directory }} 104 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.publishproj 178 | 179 | # Uncomment the next line if you don't want to checkin Publisher Profiles. 180 | # *.pubxml 181 | 182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 183 | # checkin your Azure Web App publish settings, but sensitive information contained 184 | # in these scripts will be unencrypted 185 | PublishScripts/ 186 | 187 | # NuGet Packages 188 | *.nupkg 189 | # NuGet Symbol Packages 190 | *.snupkg 191 | # The packages folder can be ignored because of Package Restore 192 | **/[Pp]ackages/* 193 | # except build/, which is used as an MSBuild target. 194 | !**/[Pp]ackages/build/ 195 | # Uncomment if necessary however generally it will be regenerated when needed 196 | #!**/[Pp]ackages/repositories.config 197 | # NuGet v3's project.json files produces more ignorable files 198 | *.nuget.props 199 | *.nuget.targets 200 | 201 | # Microsoft Azure Build Output 202 | csx/ 203 | *.build.csdef 204 | 205 | # Microsoft Azure Emulator 206 | ecf/ 207 | rcf/ 208 | 209 | # Windows Store app package directories and files 210 | AppPackages/ 211 | BundleArtifacts/ 212 | Package.StoreAssociation.xml 213 | _pkginfo.txt 214 | *.appx 215 | *.appxbundle 216 | *.appxupload 217 | 218 | # Visual Studio cache files 219 | # files ending in .cache can be ignored 220 | *.[Cc]ache 221 | # but keep track of directories ending in .cache 222 | !?*.[Cc]ache/ 223 | 224 | # Others 225 | ClientBin/ 226 | ~$* 227 | *~ 228 | *.dbmdl 229 | *.dbproj.schemaview 230 | *.jfm 231 | *.pfx 232 | *.publishsettings 233 | orleans.codegen.cs 234 | 235 | # Including strong name files can present a security risk 236 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 237 | #*.snk 238 | 239 | # Since there are multiple workflows, uncomment next line to ignore bower_components 240 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 241 | #bower_components/ 242 | 243 | # RIA/Silverlight projects 244 | Generated_Code/ 245 | 246 | # Backup & report files from converting an old project file 247 | # to a newer Visual Studio version. Backup files are not needed, 248 | # because we have git ;-) 249 | _UpgradeReport_Files/ 250 | Backup*/ 251 | UpgradeLog*.XML 252 | UpgradeLog*.htm 253 | ServiceFabricBackup/ 254 | *.rptproj.bak 255 | 256 | # SQL Server files 257 | *.mdf 258 | *.ldf 259 | *.ndf 260 | 261 | # Business Intelligence projects 262 | *.rdl.data 263 | *.bim.layout 264 | *.bim_*.settings 265 | *.rptproj.rsuser 266 | *- [Bb]ackup.rdl 267 | *- [Bb]ackup ([0-9]).rdl 268 | *- [Bb]ackup ([0-9][0-9]).rdl 269 | 270 | # Microsoft Fakes 271 | FakesAssemblies/ 272 | 273 | # GhostDoc plugin setting file 274 | *.GhostDoc.xml 275 | 276 | # Node.js Tools for Visual Studio 277 | .ntvs_analysis.dat 278 | node_modules/ 279 | 280 | # Visual Studio 6 build log 281 | *.plg 282 | 283 | # Visual Studio 6 workspace options file 284 | *.opt 285 | 286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 287 | *.vbw 288 | 289 | # Visual Studio LightSwitch build output 290 | **/*.HTMLClient/GeneratedArtifacts 291 | **/*.DesktopClient/GeneratedArtifacts 292 | **/*.DesktopClient/ModelManifest.xml 293 | **/*.Server/GeneratedArtifacts 294 | **/*.Server/ModelManifest.xml 295 | _Pvt_Extensions 296 | 297 | # Paket dependency manager 298 | .paket/paket.exe 299 | paket-files/ 300 | 301 | # FAKE - F# Make 302 | .fake/ 303 | 304 | # CodeRush personal settings 305 | .cr/personal 306 | 307 | # Python Tools for Visual Studio (PTVS) 308 | __pycache__/ 309 | *.pyc 310 | 311 | # Cake - Uncomment if you are using it 312 | # tools/** 313 | # !tools/packages.config 314 | 315 | # Tabs Studio 316 | *.tss 317 | 318 | # Telerik's JustMock configuration file 319 | *.jmconfig 320 | 321 | # BizTalk build output 322 | *.btp.cs 323 | *.btm.cs 324 | *.odx.cs 325 | *.xsd.cs 326 | 327 | # OpenCover UI analysis results 328 | OpenCover/ 329 | 330 | # Azure Stream Analytics local run output 331 | ASALocalRun/ 332 | 333 | # MSBuild Binary and Structured Log 334 | *.binlog 335 | 336 | # NVidia Nsight GPU debugger configuration file 337 | *.nvuser 338 | 339 | # MFractors (Xamarin productivity tool) working folder 340 | .mfractor/ 341 | 342 | # Local History for Visual Studio 343 | .localhistory/ 344 | 345 | # BeatPulse healthcheck temp database 346 | healthchecksdb 347 | 348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 349 | MigrationBackup/ 350 | 351 | # Ionide (cross platform F# VS Code tools) working folder 352 | .ionide/ 353 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | This project welcomes contributions and suggestions. Most contributions require you to 4 | agree to a Contributor License Agreement (CLA) declaring that you have the right to, 5 | and actually do, grant us the rights to use your contribution. For details, visit 6 | https://cla.microsoft.com. 7 | 8 | When you submit a pull request, a CLA-bot will automatically determine whether you need 9 | to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the 10 | instructions provided by the bot. You will only need to do this once across all repositories using our CLA. 11 | 12 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 13 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 14 | or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | win-x64;win-x86 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/BadgeLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/BadgeLogo.scale-100.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/BadgeLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/BadgeLogo.scale-125.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/BadgeLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/BadgeLogo.scale-150.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/BadgeLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/BadgeLogo.scale-200.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/BadgeLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/BadgeLogo.scale-400.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/LargeTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/LargeTile.scale-100.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/LargeTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/LargeTile.scale-125.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/LargeTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/LargeTile.scale-150.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/LargeTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/LargeTile.scale-200.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/LargeTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/LargeTile.scale-400.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/SmallTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/SmallTile.scale-100.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/SmallTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/SmallTile.scale-125.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/SmallTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/SmallTile.scale-150.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/SmallTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/SmallTile.scale-200.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/SmallTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/SmallTile.scale-400.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/SplashScreen.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/SplashScreen.scale-100.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/SplashScreen.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/SplashScreen.scale-125.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/SplashScreen.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/SplashScreen.scale-150.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/SplashScreen.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/SplashScreen.scale-400.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square150x150Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square150x150Logo.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square150x150Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square150x150Logo.scale-100.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square150x150Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square150x150Logo.scale-125.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square150x150Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square150x150Logo.scale-150.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square150x150Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square150x150Logo.scale-400.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.altform-unplated_targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.altform-unplated_targetsize-16.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.altform-unplated_targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.altform-unplated_targetsize-24.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.altform-unplated_targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.altform-unplated_targetsize-256.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.altform-unplated_targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.altform-unplated_targetsize-32.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.altform-unplated_targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.altform-unplated_targetsize-48.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.scale-100.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.scale-125.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.scale-150.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.scale-400.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.targetsize-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.targetsize-16.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.targetsize-24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.targetsize-24.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.targetsize-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.targetsize-256.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.targetsize-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.targetsize-32.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/Square44x44Logo.targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/Square44x44Logo.targetsize-48.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/StoreLogo.backup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/StoreLogo.backup.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/StoreLogo.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/StoreLogo.scale-100.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/StoreLogo.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/StoreLogo.scale-125.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/StoreLogo.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/StoreLogo.scale-150.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/StoreLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/StoreLogo.scale-200.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/StoreLogo.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/StoreLogo.scale-400.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/WideTile.scale-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/WideTile.scale-100.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/WideTile.scale-125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/WideTile.scale-125.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/WideTile.scale-150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/WideTile.scale-150.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/WideTile.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/WideTile.scale-200.png -------------------------------------------------------------------------------- /MyWPFApp.Package/Images/WideTile.scale-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp.Package/Images/WideTile.scale-400.png -------------------------------------------------------------------------------- /MyWPFApp.Package/MyWPFApp.Package.wapproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 15.0 5 | 6 | 7 | 8 | Debug 9 | x86 10 | 11 | 12 | Release 13 | x86 14 | 15 | 16 | Debug 17 | x64 18 | 19 | 20 | Release 21 | x64 22 | 23 | 24 | Debug 25 | AnyCPU 26 | 27 | 28 | Release 29 | AnyCPU 30 | 31 | 32 | 33 | $(MSBuildExtensionsPath)\Microsoft\DesktopBridge\ 34 | 35 | 36 | 37 | 0536b61a-90cf-428d-b4f8-cf011b3a0830 38 | 10.0.19041.0 39 | 10.0.17763.0 40 | en-US 41 | 42 | True 43 | 48 | 49 | 50 | 51 | 52 | True 53 | 54 | neutral 55 | 56 | https://microsoft.github.io/github-actions-for-desktop-apps-distribution-local 57 | False 58 | ..\MyWPFApp\MyWPFApp.csproj 59 | 0 60 | OnApplicationRun 61 | True 62 | SHA256 63 | 64 | 65 | Always 66 | 67 | 68 | Always 69 | 70 | 71 | Always 72 | 73 | 74 | Always 75 | 76 | 77 | Always 78 | 79 | 80 | Always 81 | 82 | 83 | 84 | Designer 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | True 95 | Full 96 | Properties\PublishProfiles\SelfContainedWin86.pubxml 97 | Properties\PublishProfiles\SelfContainedWin64.pubxml 98 | Properties\PublishProfiles\SelfContainedWin86Debug.pubxml 99 | Properties\PublishProfiles\SelfContainedWin64Debug.pubxml 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /MyWPFApp.Package/Package.appinstaller: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /MyWPFApp.Package/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 8 | 9 | 13 | 14 | 15 | MyWPFApp (Local) 16 | Build 17 | Images\StoreLogo.png 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /MyWPFApp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28817.109 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyWPFApp", "MyWPFApp\MyWPFApp.csproj", "{044FC6EF-3251-4AC0-BC2E-C90C16A068CB}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4F26147B-A031-40ED-9CA1-A765A6997816}" 9 | ProjectSection(SolutionItems) = preProject 10 | .gitignore = .gitignore 11 | .github\workflows\cd.yml = .github\workflows\cd.yml 12 | .github\workflows\ci.yml = .github\workflows\ci.yml 13 | Directory.Build.props = Directory.Build.props 14 | global.json = global.json 15 | README.md = README.md 16 | version.json = version.json 17 | EndProjectSection 18 | EndProject 19 | Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "MyWPFApp.Package", "MyWPFApp.Package\MyWPFApp.Package.wapproj", "{0536B61A-90CF-428D-B4F8-CF011B3A0830}" 20 | EndProject 21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyWPFApp.Tests", "MyWpfApp.Tests\MyWPFApp.Tests.csproj", "{203E0C07-10FC-450B-8D92-F6AA50167946}" 22 | EndProject 23 | Global 24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 25 | Debug|Any CPU = Debug|Any CPU 26 | Debug|x64 = Debug|x64 27 | Debug|x86 = Debug|x86 28 | Release|Any CPU = Release|Any CPU 29 | Release|x64 = Release|x64 30 | Release|x86 = Release|x86 31 | EndGlobalSection 32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 33 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Debug|x64.ActiveCfg = Debug|Any CPU 36 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Debug|x64.Build.0 = Debug|Any CPU 37 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Debug|x86.ActiveCfg = Debug|Any CPU 38 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Debug|x86.Build.0 = Debug|Any CPU 39 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Release|x64.ActiveCfg = Release|Any CPU 42 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Release|x64.Build.0 = Release|Any CPU 43 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Release|x86.ActiveCfg = Release|Any CPU 44 | {044FC6EF-3251-4AC0-BC2E-C90C16A068CB}.Release|x86.Build.0 = Release|Any CPU 45 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 46 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Debug|Any CPU.Build.0 = Debug|Any CPU 47 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 48 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Debug|x64.ActiveCfg = Debug|x64 49 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Debug|x64.Build.0 = Debug|x64 50 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Debug|x64.Deploy.0 = Debug|x64 51 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Debug|x86.ActiveCfg = Debug|x86 52 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Debug|x86.Build.0 = Debug|x86 53 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Debug|x86.Deploy.0 = Debug|x86 54 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Release|Any CPU.ActiveCfg = Release|x86 55 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Release|Any CPU.Build.0 = Release|x86 56 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Release|Any CPU.Deploy.0 = Release|x86 57 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Release|x64.ActiveCfg = Release|x64 58 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Release|x64.Build.0 = Release|x64 59 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Release|x64.Deploy.0 = Release|x64 60 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Release|x86.ActiveCfg = Release|x86 61 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Release|x86.Build.0 = Release|x86 62 | {0536B61A-90CF-428D-B4F8-CF011B3A0830}.Release|x86.Deploy.0 = Release|x86 63 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 64 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Debug|Any CPU.Build.0 = Debug|Any CPU 65 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Debug|x64.ActiveCfg = Debug|Any CPU 66 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Debug|x64.Build.0 = Debug|Any CPU 67 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Debug|x86.ActiveCfg = Debug|Any CPU 68 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Debug|x86.Build.0 = Debug|Any CPU 69 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Release|Any CPU.ActiveCfg = Release|Any CPU 70 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Release|Any CPU.Build.0 = Release|Any CPU 71 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Release|x64.ActiveCfg = Release|Any CPU 72 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Release|x64.Build.0 = Release|Any CPU 73 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Release|x86.ActiveCfg = Release|Any CPU 74 | {203E0C07-10FC-450B-8D92-F6AA50167946}.Release|x86.Build.0 = Release|Any CPU 75 | EndGlobalSection 76 | GlobalSection(SolutionProperties) = preSolution 77 | HideSolutionNode = FALSE 78 | EndGlobalSection 79 | GlobalSection(ExtensibilityGlobals) = postSolution 80 | SolutionGuid = {FE785289-C15B-4F37-AA72-8EFFD2710DDD} 81 | EndGlobalSection 82 | EndGlobal 83 | -------------------------------------------------------------------------------- /MyWPFApp/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /MyWPFApp/App.xaml.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Configuration; 7 | using System.Data; 8 | using System.Linq; 9 | using System.Threading.Tasks; 10 | using System.Windows; 11 | using MyWPFApp.Telemetry; 12 | 13 | namespace MyWPFApp 14 | { 15 | /// 16 | /// Interaction logic for App.xaml 17 | /// 18 | public partial class App : Application 19 | { 20 | public App() 21 | { 22 | DiagnosticsClient.Initialize(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MyWPFApp/ApplicationInsights.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /MyWPFApp/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 63 | 64 | -------------------------------------------------------------------------------- /MyWPFApp/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Windows; 3 | using OSVersionHelper; 4 | 5 | using MyWPFApp.Telemetry; 6 | 7 | namespace MyWPFApp 8 | { 9 | /// 10 | /// Interaction logic for MainWindow.xaml 11 | /// 12 | public partial class MainWindow : Window 13 | { 14 | public MainWindow() 15 | { 16 | InitializeComponent(); 17 | 18 | packageName.Text = ThisAppInfo.GetDisplayName(); 19 | assemblyVersion.Text = ThisAppInfo.GetThisAssemblyVersion(); 20 | packageVersion.Text = ThisAppInfo.GetPackageVersion(); 21 | installedFrom.Text = ThisAppInfo.GetAppInstallerUri(); 22 | installLocation.Text = ThisAppInfo.GetInstallLocation(); 23 | DiagnosticsClient.TrackPageView(nameof(MainWindow)); 24 | } 25 | private void Button_Click(object sender, RoutedEventArgs e) 26 | { 27 | DiagnosticsClient.TrackEvent("ClickShowRuntimeInfo"); 28 | 29 | if (ButtonShowRuntimeVersionInfo.Content.ToString().StartsWith("Show")) 30 | { 31 | RuntimeVersionInfo.Text = ThisAppInfo.GetDotNetRuntimeInfo(); 32 | ButtonShowRuntimeVersionInfo.Content = "Hide Runtime Info"; 33 | } 34 | else 35 | { 36 | RuntimeVersionInfo.Text = ""; 37 | ButtonShowRuntimeVersionInfo.Content = "Show Runtime Info"; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /MyWPFApp/MyWPFApp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | netcoreapp3.1 6 | true 7 | win.ico 8 | win-x86;win-x64 9 | 10.0.17134.0 10 | MyWPFApp.App 11 | 12 | 13 | $(Platform) 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /MyWPFApp/Properties/PublishProfiles/SelfContainedWin64.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | FileSystem 8 | Release 9 | x64 10 | netcoreapp3.1 11 | bin\Release\netcoreapp3.1\publish\ 12 | win-x64 13 | true 14 | False 15 | False 16 | False 17 | 18 | -------------------------------------------------------------------------------- /MyWPFApp/Properties/PublishProfiles/SelfContainedWin64Debug.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | FileSystem 8 | Debug 9 | x64 10 | netcoreapp3.1 11 | bin\Debug\netcoreapp3.1\publish\ 12 | win-x64 13 | true 14 | False 15 | False 16 | False 17 | 18 | -------------------------------------------------------------------------------- /MyWPFApp/Properties/PublishProfiles/SelfContainedWin86.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | FileSystem 8 | Release 9 | x86 10 | netcoreapp3.1 11 | bin\Release\netcoreapp3.1\publish\ 12 | win-x86 13 | true 14 | False 15 | False 16 | False 17 | 18 | -------------------------------------------------------------------------------- /MyWPFApp/Properties/PublishProfiles/SelfContainedWin86Debug.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | FileSystem 8 | Debug 9 | x86 10 | netcoreapp3.1 11 | bin\Debug\netcoreapp3.1\publish\ 12 | win-x86 13 | true 14 | False 15 | False 16 | False 17 | 18 | -------------------------------------------------------------------------------- /MyWPFApp/Telemetry/AppVersionTelemetryInitializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using Microsoft.ApplicationInsights.Channel; 7 | using Microsoft.ApplicationInsights.Extensibility; 8 | 9 | namespace MyWPFApp.Telemetry 10 | { 11 | internal class AppVersionTelemetryInitializer : ITelemetryInitializer 12 | { 13 | private readonly string _wpfVersion; 14 | private readonly string _appVersion; 15 | 16 | public AppVersionTelemetryInitializer() 17 | { 18 | _wpfVersion = typeof(System.Windows.Application).Assembly.GetCustomAttribute().InformationalVersion; 19 | _appVersion = ThisAppInfo.GetPackageVersion(); 20 | } 21 | 22 | public void Initialize(ITelemetry telemetry) 23 | { 24 | telemetry.Context.GlobalProperties["WPF version"] = _wpfVersion; 25 | telemetry.Context.Component.Version = _appVersion; 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /MyWPFApp/Telemetry/DiagnosticsClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Text; 5 | using Microsoft.ApplicationInsights; 6 | using Microsoft.ApplicationInsights.Extensibility; 7 | 8 | namespace MyWPFApp.Telemetry 9 | { 10 | public static class DiagnosticsClient 11 | { 12 | private static bool _initialized; 13 | private static TelemetryClient _client; 14 | 15 | public static void Initialize() 16 | { 17 | TelemetryConfiguration.Active.TelemetryInitializers.Add(new AppVersionTelemetryInitializer()); 18 | TelemetryConfiguration.Active.TelemetryInitializers.Add(new EnvironmentTelemetryInitializer()); 19 | 20 | _initialized = true; 21 | _client = new TelemetryClient(); 22 | System.Windows.Application.Current.Startup += Application_Startup; 23 | System.Windows.Application.Current.Exit += Application_Exit; 24 | System.Windows.Application.Current.DispatcherUnhandledException += DispatcherUnhandledException; 25 | } 26 | 27 | private static void DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) 28 | { 29 | TrackException(e.Exception); 30 | } 31 | 32 | private static void Application_Exit(object sender, System.Windows.ExitEventArgs e) 33 | { 34 | TrackEvent("AppExit"); 35 | _client.Flush(); 36 | // Allow time for flushing: 37 | System.Threading.Thread.Sleep(1000); 38 | } 39 | 40 | private static void Application_Startup(object sender, System.Windows.StartupEventArgs e) 41 | { 42 | TrackEvent("AppStart"); 43 | } 44 | 45 | public static void TrackEvent(string eventName, IDictionary properties = null, IDictionary metrics = null) 46 | { 47 | if (!_initialized) return; 48 | _client.TrackEvent(eventName, properties, metrics); 49 | } 50 | 51 | public static void TrackTrace(string evt) 52 | { 53 | if (!_initialized) return; 54 | _client.TrackTrace(evt); 55 | } 56 | 57 | public static void TrackException(Exception exception, IDictionary properties = null, IDictionary metrics = null) 58 | { 59 | if (!_initialized) return; 60 | _client.TrackException(exception, properties, metrics); 61 | } 62 | 63 | public static void TrackPageView(string pageName) 64 | { 65 | if (!_initialized) return; 66 | _client.TrackPageView(pageName); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /MyWPFApp/Telemetry/EnvironmentTelemetryInitializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Security.Cryptography; 7 | using System.Text; 8 | using Microsoft.ApplicationInsights.Channel; 9 | using Microsoft.ApplicationInsights.Extensibility; 10 | 11 | namespace MyWPFApp.Telemetry 12 | { 13 | internal class EnvironmentTelemetryInitializer : ITelemetryInitializer 14 | { 15 | public void Initialize(ITelemetry telemetry) 16 | { 17 | telemetry.Context.GlobalProperties["Environment"] = ThisAppInfo.GetPackageChannel() ?? "Local"; 18 | 19 | // Always default to Local if we're in the debugger 20 | if (Debugger.IsAttached) 21 | { 22 | telemetry.Context.GlobalProperties["Environment"] = "Local"; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /MyWPFApp/ThisAppInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | 4 | using System; 5 | using System.IO; 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | 9 | using OSVersionHelper; 10 | 11 | using Windows.ApplicationModel; 12 | using Windows.Foundation.Metadata; 13 | 14 | namespace MyWPFApp 15 | { 16 | public class ThisAppInfo 17 | { 18 | public static string GetDisplayName() 19 | { 20 | if (WindowsVersionHelper.HasPackageIdentity) 21 | { 22 | return Package.Current.DisplayName; 23 | } 24 | return "Not packaged"; 25 | } 26 | 27 | internal static string GetThisAssemblyVersion() 28 | { 29 | return typeof(MainWindow).Assembly.GetCustomAttribute().InformationalVersion; 30 | } 31 | 32 | internal static string GetInstallLocation() 33 | { 34 | return Assembly.GetExecutingAssembly().Location; 35 | } 36 | 37 | internal static string GetPackageVersion() 38 | { 39 | if (WindowsVersionHelper.HasPackageIdentity) 40 | { 41 | return $"{Package.Current.Id.Version.Major}.{Package.Current.Id.Version.Minor}.{Package.Current.Id.Version.Build}.{Package.Current.Id.Version.Revision}"; 42 | } 43 | return "Not packaged"; 44 | } 45 | 46 | internal static string GetPackageChannel() 47 | { 48 | if(WindowsVersionHelper.HasPackageIdentity) 49 | { 50 | return Package.Current.Id.Name.Substring(Package.Current.Id.Name.LastIndexOf('.') + 1); 51 | } 52 | 53 | return null; 54 | } 55 | 56 | internal static string GetDotNetInfo() 57 | { 58 | var runTimeDir = new FileInfo(typeof(string).Assembly.Location); 59 | var entryDir = new FileInfo(Assembly.GetEntryAssembly().Location); 60 | var IsSelfContaied = runTimeDir.DirectoryName == entryDir.DirectoryName; 61 | 62 | var result = ".NET Framework - "; 63 | if (IsSelfContaied) 64 | { 65 | result += "Self Contained Deployment"; 66 | } 67 | else 68 | { 69 | result += "Framework Dependent Deployment"; 70 | } 71 | 72 | return result; 73 | } 74 | 75 | public static string GetAppInstallerUri() 76 | { 77 | string result; 78 | 79 | if (!WindowsVersionHelper.HasPackageIdentity) return "Not packaged"; 80 | 81 | if (ApiInformation.IsMethodPresent("Windows.ApplicationModel.Package", "GetAppInstallerInfo")) 82 | { 83 | var aiUri = GetAppInstallerInfoUri(Package.Current); 84 | if (aiUri != null) 85 | { 86 | result = aiUri.ToString(); 87 | } 88 | else 89 | { 90 | result = "not present"; 91 | } 92 | } 93 | else 94 | { 95 | result = "Not Available"; 96 | } 97 | 98 | return result; 99 | } 100 | 101 | internal static string GetDotNetRuntimeInfo() 102 | { 103 | return typeof(object).Assembly.GetCustomAttribute().InformationalVersion; 104 | } 105 | 106 | [MethodImpl(MethodImplOptions.NoInlining)] 107 | private static Uri GetAppInstallerInfoUri(Package p) 108 | { 109 | var aiInfo = p.GetAppInstallerInfo(); 110 | if (aiInfo != null) 111 | { 112 | return aiInfo.Uri; 113 | } 114 | return null; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /MyWPFApp/win.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/MyWPFApp/win.ico -------------------------------------------------------------------------------- /MyWpfApp.Tests/MyWPFApp.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /MyWpfApp.Tests/ThisAppInfoTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT license. 3 | 4 | using NUnit.Framework; 5 | using MyWPFApp; 6 | 7 | namespace MyWPFApp.Tests 8 | { 9 | public class Tests 10 | { 11 | [SetUp] 12 | public void Setup() 13 | { 14 | var thisAppInfo = new ThisAppInfo(); 15 | } 16 | 17 | [Test] 18 | public void GetDisplayName() 19 | { 20 | var displayName = ThisAppInfo.GetDisplayName(); 21 | Assert.AreEqual("Not packaged", displayName); 22 | } 23 | 24 | [Test] 25 | public void GetAppInstallerUri() 26 | { 27 | var appInstallerUri = ThisAppInfo.GetAppInstallerUri(); 28 | 29 | Assert.AreEqual("Not packaged", appInstallerUri); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DevOps for Windows Desktop Apps Using GitHub Actions 2 | 3 | ### Create CI/CD workflows for WPF and Windows Forms Applications built on .NET Core 3.x 4 | 5 | This repo contains a sample application to demonstrate how to create CI/CD pipelines using [GitHub Actions](https://github.com/features/actions "GitHub Actions page"). 6 | 7 | With GitHub Actions, you can quickly and easily automate your software workflows with CI/CD. 8 | * Integrate code changes directly into GitHub to speed up development cycles 9 | * Trigger builds to quickly identify breaking changes and create testable debug builds 10 | * Continuously run tests to identify and eliminate bugs, improving code quality 11 | * Automatically build, sign, package and deploy branches that pass CI 12 | 13 | Build, test, and deploy your code entirely within GitHub. 14 | 15 | | Workflow | Status | 16 | |----------|--------| 17 | | WPF - CI | ![ci](https://github.com/microsoft/github-actions-for-desktop-apps/workflows/Wpf%20Continuous%20Integration/badge.svg) | 18 | | WPF - CD | ![cd](https://github.com/microsoft/github-actions-for-desktop-apps/workflows/Wpf%20Continuous%20Delivery/badge.svg) | 19 | | WPF - CI (.NET 6 experimental) | [![NET 6.0 CI (temporary)](https://github.com/microsoft/github-actions-for-desktop-apps/actions/workflows/ci-net6-temp.yml/badge.svg)](https://github.com/microsoft/github-actions-for-desktop-apps/actions/workflows/ci-net6-temp.yml) | 20 | 21 | ## Workflows 22 | 23 | To take advantage of GitHub Actions, workflows are defined in YAML files that are in the .github/workflows folder. 24 | In the project, there are two workflows defined: 25 | 26 | * .github/workflows/ci.yml 27 | * .github/workflows/cd.yml 28 | 29 | The ci.yml file defines the continuous integration workflow which is used to build, test, and create a package every time a developer pushes code to the repo. 30 | 31 | The benefits of kicking off a CI run on every push are multi-fold: 32 | * Quickly identify breaking changes 33 | * Create a testable debug build 34 | * Continuously run tests to identify and eliminate bugs, improving code quality 35 | * Keep workflow relatively lightweight by only testing configurations necessary to ensure good quality 36 | 37 | The cd.yml file defines our continuous delivery workflow used to build, sign, package and archive release assets for every configuration that is planned for release. 38 | 39 | 40 | ### ci.yml: Build, test, package, and save package artifacts. 41 | 42 | The CI workflow defines the Package.Identity.Name in the Windows Application Packaging project’s Package.appxmanifest to identify the application as "MyWPFApp.DevOpsDemo.Local." By suffixing the application name with ".Local," developers are able to install it side by side with other channels of the app. 43 | ```yaml 44 | 48 | ``` 49 | 50 | On every push to the repo, take advantage of the [setup-dotnet](https://github.com/actions/setup-dotnet "Setup dotnet GitHub Action") GitHub Action and install the [dotnet core cli](https://github.com/dotnet/cli "DotNet Core CLI page") environment. Then add [MSBuild](https://github.com/microsoft/setup-msbuild "MSBuild GitHub Action page") to the PATH and execute unit tests using the [dotnet test](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test "DotNet test page") runner console application. 51 | ```yaml 52 | - name: Install .NET Core 53 | uses: actions/setup-dotnet@v1 54 | with: 55 | dotnet-version: 3.1.100 56 | 57 | # Add MsBuild to the PATH: https://github.com/microsoft/setup-msbuild 58 | - name: Setup MSBuild.exe 59 | uses: microsoft/setup-msbuild@v1.0.0 60 | 61 | # Test 62 | - name: Execute Unit Tests 63 | run: dotnet test $env:Test_Project_Path 64 | ``` 65 | 66 | As mentioned above, you can target multiple platforms by authoring the workflow file to define a build matrix, a set of different configurations that are each run in a fresh instance of a virtual environment by the [GitHub-hosted runner](https://help.github.com/en/actions/getting-started-with-github-actions/core-concepts-for-github-actions#github-hosted-runner "GitHub Hosted Runner page"). 67 | 68 | In the continuous integration workflow, create a release build for x86 and x64 that runs on the latest windows OS installed on the GitHub-hosted runners. Then, define [environment variables](https://help.github.com/en/actions/configuring-and-managing-workflows/using-environment-variables "Configuring and Managing Workflows Using Environment Variables page") that are common to all the runs in the matrix such as the signing certificate name, the relative path to the solution file and the Windows Application Packaging project name. 69 | ```yaml 70 | strategy: 71 | matrix: 72 | targetplatform: [x86, x64] 73 | 74 | runs-on: windows-latest 75 | 76 | env: 77 | SigningCertificate: GitHubActionsDemo.pfx 78 | Solution_Path: MyWpfApp.sln 79 | Test_Project_Path: MyWpfApp.Tests\MyWpfApp.Tests.csproj 80 | Wpf_Project_Path: MyWpfApp\MyWpfApp.csproj 81 | Wap_Project_Directory: MyWpfApp.Package 82 | Wap_Project_Name: MyWpfApp.Package.wapproj 83 | ``` 84 | 85 | Next, execute the unit tests in MYWPFApp.Tests by calling ‘donet test’. 86 | ```yaml 87 | # Test 88 | - name: Execute Unit Tests 89 | run: dotnet test $env:Test_Project_Path 90 | ``` 91 | 92 | After executing the tests, restore the application while passing in the RuntimeIdentifier parameter in order to populate the obj folder with the appropriate platform dependencies for use during build. 93 | ```yaml 94 | # Restore the application 95 | - name: Restore the Wpf application to populate the obj folder 96 | run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier 97 | env: 98 | Configuration: Debug 99 | RuntimeIdentifier: win-${{ matrix.targetplatform }} 100 | ``` 101 | 102 | Once the application has been restored, build and create the MSIX. Rather than build each project separately, simply build the solution, making sure to pass the target platform, configuration, build mode, whether to produce an app bundle, the signing certificate, and certificate password as parameters. 103 | ```yaml 104 | # Build the Windows Application Packaging project 105 | - name: Build the Windows Application Packaging Project (wapproj) 106 | run: msbuild $env:Solution_Path /p:Platform=$env:TargetPlatform /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:BuildMode /p:AppxBundle=$env:AppxBundle /p:PackageCertificateKeyFile=$env:SigningCertificate /p:PackageCertificatePassword=${{ secrets.Pfx_Key }} 107 | env: 108 | AppxBundle: Never 109 | BuildMode: SideLoadOnly 110 | Configuration: Release 111 | TargetPlatform: ${{ matrix.targetplatform }} 112 | ``` 113 | 114 | Once the app package has been created, take advantage of the [upload-artifact](https://github.com/marketplace/actions/upload-artifact "upload-artifact GitHub Action page") GitHub Action to save the artifact. You have the option to download the artifact to test the build or upload the artifact to a website or file share to distribute the application. 115 | ```yaml 116 | # Upload the MSIX package: https://github.com/marketplace/actions/upload-artifact 117 | - name: Upload build artifacts 118 | uses: actions/upload-artifact@v1 119 | with: 120 | name: MSIX Package 121 | path: MyWpfApp.Package\AppPackages\ 122 | ``` 123 | 124 | To find the artifact, navigate to "Actions," select the workflow, then download the artifact on the right side of the window. 125 | ![](doc/images/findArtifact.png) 126 | 127 | 128 | ### cd.yml: Build, package, and create a GitHub release for multiple channels 129 | 130 | In the CD workflow, you can build, package and distribute code built for multiple channels such as “Dev”, “Prod_Sideload” and “Prod_Store.” During every workflow run, the applications’ Package.Identity.Name, Package.Identity.Version and Package.Properties.DisplayName are changed according to which channel of the build matrix will be built. 131 | We use a Powershell script to overwrite these values in the Windows Application Packaging project's Package.appxmanifest. By doing so, we change the identity of the application to *MyWPFApp.DevOpsDemo.Dev*, *MyWPFApp.DevOpsDemo.ProdSideload*, or *MyWPFApp.DevOpsDemo.ProdStore* depending on which matrix channel is built, thus enabling multiple channels of the application. 132 | ```yaml 133 | # Update the appxmanifest before build by setting the per-channel values set in the matrix. 134 | - name: Update manifest version 135 | run: | 136 | [xml]$manifest = get-content ".\$env:Wap_Project_Directory\Package.appxmanifest" 137 | $manifest.Package.Identity.Version = "$env:NBGV_SimpleVersion.0" 138 | $manifest.Package.Identity.Name = "${{ matrix.MsixPackageId }}" 139 | $manifest.Package.Identity.Publisher = "${{ matrix.MsixPublisherId }}" 140 | $manifest.Package.Properties.DisplayName = "${{ matrix.MsixPackageDisplayName }}" 141 | $manifest.Package.Applications.Application.VisualElements.DisplayName = "${{ matrix.MsixPackageDisplayName }}" 142 | $manifest.save(".\$env:Wap_Project_Directory\Package.appxmanifest") 143 | ``` 144 | 145 | On every push to the repo with a tag matching the pattern *, the workflow will build the solution, create a release and upload the release asset. For more information on how to configure a workflow to run on specific branches or tags, see [GitHub Workflow syntax for GitHub Actions - on..](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#onpushpull_requestbranchestags "GitHub Workflow Syntax for GitHub Actions"). 146 | ```yaml 147 | on: 148 | push: 149 | tags: 150 | - '*' 151 | ``` 152 | 153 | To create a git `tag`, run the following commands on the branch you wish to release: 154 | ```cmd 155 | git tag 1.0.0.0 156 | git push origin --tags 157 | ``` 158 | 159 | The above commands will add the tag "1.0.0.0" and then `push` the branch and tag to the repo. Learn more about [Git Tagging.](https://git-scm.com/book/en/v2/Git-Basics-Tagging "Basics of Git Tagging") 160 | 161 | Channels and environment variables used during the run are defined in the build matrix and will build and create app packages for development (Dev), production sideload (Prod_Sideload), and also production for the [Microsoft Store](https://www.microsoft.com/en-us/store/apps/windows "Microsoft Store home page") (Prod_Store). In this example, each channel is built for two configurations: x86 and x64. However, arm or arm64 are valid configurations as well. 162 | 163 | A build matrix can be created to execute jobs across multiple operating systems, build configurations or different supported versions of a programming language. With GitHub Actions, you can define incredibly complex build matrices that can generate up to 256 builds per run! Learn how to [configure a build matrix.](https://help.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow#configuring-a-build-matrix "Learn how to configure a build matrix page") 164 | ```yaml 165 | jobs: 166 | 167 | build: 168 | 169 | strategy: 170 | matrix: 171 | channel: [Dev, Prod_Sideload, Prod_Store] 172 | targetPlatform: [x86, x64] 173 | include: 174 | 175 | # includes the following variables for the matrix leg matching Dev 176 | - channel: Dev 177 | ChannelName: Dev 178 | Configuration: Debug 179 | DistributionUrl: https://microsoft.github.io/github-actions-for-desktop-apps-distribution-dev 180 | MsixPackageId: MyWPFApp.DevOpsDemo.Dev 181 | MsixPublisherId: CN=GitHubActionsDemo 182 | MsixPackageDisplayName: MyWPFApp (Dev) 183 | 184 | # includes the following variables for the matrix leg matching Prod_Sideload 185 | - channel: Prod_Sideload 186 | Configuration: Release 187 | ChannelName: Prod_Sideload 188 | DistributionUrl: https://microsoft.github.io/github-actions-for-desktop-apps-distribution-prod 189 | MsixPackageId: MyWPFApp.DevOpsDemo.ProdSideload 190 | MsixPublisherId: CN=GitHubActionsDemo 191 | MsixPackageDisplayName: MyWPFApp (ProdSideload) 192 | 193 | # includes the following variables for the matrix leg matching Prod_Store 194 | - channel: Prod_Store 195 | Configuration: Release 196 | ChannelName: Prod_Store 197 | DistributionUrl: 198 | MsixPackageId: MyWPFApp.DevOpsDemo.ProdStore 199 | MsixPublisherId: CN=GitHubActionsDemo 200 | MsixPackageDisplayName: MyWPFApp (ProdStore) 201 | ``` 202 | Just like the CI workflow, restore the solution. 203 | ```yaml 204 | # Restore the application 205 | - name: Restore the Wpf application to populate the obj folder 206 | run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier 207 | env: 208 | Configuration: Debug 209 | RuntimeIdentifier: win-${{ matrix.targetplatform }} 210 | ``` 211 | 212 | This time, however, use GitHub’s ```if``` conditional to build and package the MSIX for Dev and Prod_Sideload (which requires an AppInstaller Uri and Signing Certificate) or for Prod_Store. 213 | We pass different parameters depending on which channel we are building for. 214 | ```yaml 215 | # Build the Windows Application Packaging project for Dev and Prod_Sideload 216 | - name: Build the Windows Application Packaging Project (wapproj) for ${{ matrix.ChannelName }} 217 | run: msbuild $env:Solution_Path /p:Platform=$env:TargetPlatform /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:BuildMode /p:AppxBundle=$env:AppxBundle /p:PackageCertificateKeyFile=$env:SigningCertificate /p:PackageCertificatePassword=${{ secrets.Pfx_Key }} 218 | if: matrix.ChannelName != 'Prod_Store' 219 | env: 220 | AppxBundle: Never 221 | AppInstallerUri: ${{ matrix.DistributionUrl }} 222 | BuildMode: SideLoadOnly 223 | Configuration: ${{ matrix.Configuration }} 224 | GenerateAppInstallerFile: True 225 | TargetPlatform: ${{ matrix.targetplatform }} 226 | 227 | # Build the Windows Application Packaging project for Prod_Store 228 | - name: Build the Windows Application Packaging Project (wapproj) for ${{ matrix.ChannelName }} 229 | run: msbuild $env:Solution_Path /p:Platform=$env:TargetPlatform /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:BuildMode /p:AppxBundle=$env:AppxBundle /p:GenerateAppInstallerFile=$env:GenerateAppInstallerFile /p:AppxPackageSigningEnabled=$env:AppxPackageSigningEnabled 230 | if: matrix.ChannelName == 'Prod_Store' 231 | env: 232 | AppxBundle: Never 233 | AppxPackageSigningEnabled: False 234 | BuildMode: StoreOnly 235 | Configuration: ${{ matrix.Configuration }} 236 | GenerateAppInstallerFile: False 237 | TargetPlatform: ${{ matrix.targetplatform }} 238 | ``` 239 | 240 | Once the MSIX is created for each channel, the agent archives the AppPackages folder then creates a Release with the specified git release tag. The archive is uploaded to the release as an asset for storage or distribution. 241 | It’s important to note that release names must be unique or an error will be generated. This is why tag_name and release_name include the github reference, channel name and target platform. 242 | ```yaml 243 | # Create the release: https://github.com/actions/create-release 244 | - name: Create release 245 | id: create_release 246 | uses: actions/create-release@v1 247 | env: 248 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token 249 | with: 250 | tag_name: ${{ github.ref}}.${{matrix.ChannelName}}.${{ matrix.targetplatform }} 251 | release_name: ${{ github.ref }}.${{ matrix.ChannelName }}.${{ matrix.targetplatform }} 252 | draft: false 253 | prerelease: false 254 | 255 | # Upload release asset: https://github.com/actions/upload-release-asset 256 | - name: Update release asset 257 | id: upload-release-asset 258 | uses: actions/upload-release-asset@v1 259 | env: 260 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 261 | with: 262 | upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps 263 | asset_path: MyWpfApp.Package\AppPackages\AppPackages.zip 264 | asset_name: AppPackages.zip 265 | asset_content_type: application/zip 266 | 267 | ``` 268 | 269 | To find the Release artifacts, navigate to the "Releases" link in the repo. 270 | ![](doc/images/releases.png) 271 | 272 | Find the release and asset location. 273 | ![](doc/images/releaseAssetLocation.png) 274 | 275 | Creating channels for the application is a powerful way to create multiple distributions of an application in the same CD pipeline. 276 | 277 | 278 | ### Versioning 279 | 280 | In both workflows, one of the first things to do is create a version and store version information as environment variables. Having a different version for every push is especially important when a release is created as each release must have a unique release_name. 281 | 282 | The [Nerdbank.GitVersioning GitHub Action](https://github.com/AArnott/nbgv "Nerbank.GitVersioning GitHub Action page") sets the build version based on a combination of the included version.json file, and the git height of the version. 283 | ```yaml 284 | # Use Nerdbank.GitVersioning to set version variables: https://github.com/AArnott/nbgv 285 | - name: Use Nerdbank.GitVersioning to set version variables 286 | uses: aarnott/nbgv@v0.3 287 | with: 288 | setAllVars: true 289 | ``` 290 | 291 | Once the action runs, a number of environment variables are available for use, such as: 292 | * NBGV_Version (e.g. 1.1.159.47562) 293 | * NBGV_SimpleVersion (e.g. 1.1.159) 294 | * NBGV_NuGetPackageVersion (e.g. 1.1.159-gcab9873dd7) 295 | * NBGV_ChocolateyPackageVersion 296 | * NBGV_NpmPackageVersion 297 | 298 | A list of all the environment variables available to use in the run are shown below. 299 | ![Environment variables set by NBGV.](doc/images/versionEnvironmentVariables.png) 300 | 301 | See the [Nerdbank.GitVersioning](https://github.com/aarnott/nerdbank.gitversioning "Nerdbank.GitVersioning page") package for more information. 302 | 303 | 304 | ### Signing 305 | Avoid submitting certificates to the repo if at all possible to ensure security best practices. (Git ignores them by default.) To manage the safe handling of sensitive files like certificates, take advantage of [GitHub secrets](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets "GitHub Secrets page"), which allow the storage of sensitive information in the repository. 306 | 307 | First, generate a signing certificate in the Windows Application Packaging Project or add an existing signing certificate to the project. Next, use PowerShell to encode the .pfx file using Base64 encoding by running the following Powershell script to generate the output file. 308 | ```pwsh 309 | $pfx_cert = Get-Content '.\GitHubActionsDemo.pfx' -Encoding Byte 310 | [System.Convert]::ToBase64String($pfx_cert) | Out-File 'SigningCertificate_Encoded.txt' 311 | ``` 312 | 313 | Open the output file, *SigningCertificate_Encoded.txt*, and copy the string inside. Finally, add the string to the repo as a GitHub secret and name it Base64_Encoded_Pfx. [Learn how to add a secret to the workflow.](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners#creating-and-using-secrets-encrypted-variables "Creating and using secrets page") 314 | In the workflow, add a step to decode the secret, save the .pfx to the build agent, and package the application with the Windows Application Packaging project. 315 | ```yaml 316 | # Decode the Base64 encoded Pfx 317 | - name: Decode the Pfx 318 | run: | 319 | $pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.Base64_Encoded_Pfx }}") 320 | $currentDirectory = Get-Location 321 | $certificatePath = Join-Path -Path $currentDirectory -ChildPath $env:Wap_Project_Directory -AdditionalChildPath $env:SigningCertificate 322 | [IO.File]::WriteAllBytes("$certificatePath", $pfx_cert_byte) 323 | ``` 324 | 325 | Once the certificate is decoded and saved to the Windows Application Packaging Project, use it to sign the package during packaging making sure to pass the signing certificate's password, stored as a GitHub secret, to MSBuild as a parameter. 326 | ```yaml 327 | # Build the Windows Application Packaging project for Dev and Prod_Sideload 328 | - name: Build the Windows Application Packaging Project (wapproj) for ${{ matrix.ChannelName }} 329 | run: msbuild $env:Wap_Project_Directory/$env:Wap_Project_Name /p:Platform=$env:TargetPlatform /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:BuildMode /p:GenerateAppInstallerFile=$env:GenerateAppInstallerFile /p:AppInstallerUri=$env:AppInstallerUri /p:PackageCertificateKeyFile=$env:SigningCertificate /p:PackageCertificatePassword=${{ secrets.Pfx_Key }} 330 | if: ${{ matrix.ChannelName }} != Prod_Store 331 | env: 332 | AppInstallerUri: ${{ matrix.DistributionUrl }} 333 | BuildMode: SideLoadOnly 334 | Configuration: ${{ matrix.Configuration }} 335 | GenerateAppInstallerFile: True 336 | TargetPlatform: ${{ matrix.TargetPlatform }} 337 | ``` 338 | 339 | Finally, to ensure the certificate doesn’t stay on the build machine, delete the .pfx. 340 | ```yaml 341 | # Remove the .pfx 342 | - name: Remove the .pfx 343 | run: Remove-Item -path $env:Wap_Project_Directory/$env:SigningCertificate 344 | if: ${{ matrix.ChannelName }} != Prod_Store 345 | ``` 346 | 347 | ### Publisher Profiles 348 | Publisher Profiles allow developers to store publishing information on their WPF application such as the configuration, target runtime, and deployment mode (whether the application is self contained or framework dependent). These profiles can be easily referenced by the Windows Application Packaging project and used during build and packaging. 349 | 350 | To add a Publisher Profile to the WPF application, right-click the Wpf application and select “Publish.” In the Publish dialog, select 'New.' In the "Pick a publish target" dialog, choose the folder or file share to publish the app to and "Create Profile." 351 | ![](doc/images/pickAPublishTarget.png) 352 | 353 | In the Publish dialog, click "Edit" to customize the profile settings. 354 | ![](doc/images/editToCustomizeSettings.png) 355 | 356 | Select the configuration, framework and runtime to target, then select whether the deployment mode should be "Framework Dependent" or "Self-contained." 357 | ![](doc/images/profileSettings.png) 358 | 359 | Edit the profile name to reflect the settings by clicking "Rename" in the Publish dialog. 360 | ![](doc/images/renameProfile.png) 361 | 362 | Finally, in the Windows Application Packaging project, add a reference to the Publish Profile. 363 | In the Solution Explorer, open MyWPFApp.Package and navigate to Applications. Click on MyWFPApp and, in the properties window, select Publishing Profile. The dropdown should be populated with the recently-created profile. 364 | ![](doc/images/myWpfApp.Package.Properties.png) 365 | 366 | To ensure the settings were added correctly to MyWPFApp.Package, double click on the project to open the .wapproj file and scroll to the bottom to find the PublishProfile elements. 367 | ![](doc/images/publishProfileComplete.png) 368 | 369 | # Conclusion 370 | GitHub workflows that leverage GitHub Actions are a great way for developers to create and customize continuous integration and continuous deployment pipelines to build, test, package, publish and distribute their application from start to finish entirely in GitHub. 371 | 372 | To learn more about other GitHub Actions that you can add to your pipelines, take a look at the [GitHub Marketplace](https://github.com/marketplace?type=actions "GitHub Marketplace page"). For more information on GitHub Actions, check out the [GitHub Actions](https://github.com/features/actions "GitHub Actions home page") home page. 373 | 374 | We are always open to your feedback. Please feel free to email us at [devdeploymenttools@microsoft.com](mailto:devdeploymenttools@microsoft.com "Email us at devdeploymenttools at Microsoft.com"). 375 | 376 | Our repo is open source and welcomes contributions and suggestions. Please see [Contributing.md](https://github.com/microsoft/github-actions-for-desktop-apps/blob/master/CONTRIBUTING.md "Contributing.md page") for more information on how to submit a PR to the repo. 377 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /doc/images/editToCustomizeSettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/doc/images/editToCustomizeSettings.png -------------------------------------------------------------------------------- /doc/images/findArtifact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/doc/images/findArtifact.png -------------------------------------------------------------------------------- /doc/images/myWpfApp.Package.Properties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/doc/images/myWpfApp.Package.Properties.png -------------------------------------------------------------------------------- /doc/images/pickAPublishTarget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/doc/images/pickAPublishTarget.png -------------------------------------------------------------------------------- /doc/images/profileSettings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/doc/images/profileSettings.png -------------------------------------------------------------------------------- /doc/images/publishProfileComplete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/doc/images/publishProfileComplete.png -------------------------------------------------------------------------------- /doc/images/releaseAssetLocation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/doc/images/releaseAssetLocation.png -------------------------------------------------------------------------------- /doc/images/releases.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/doc/images/releases.png -------------------------------------------------------------------------------- /doc/images/renameProfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/doc/images/renameProfile.png -------------------------------------------------------------------------------- /doc/images/versionEnvironmentVariables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/github-actions-for-desktop-apps/fb81ac030181846f53b1c4a4cafae2c9394f3976/doc/images/versionEnvironmentVariables.png -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "publicReleaseRefSpec": [ 4 | "^refs/heads/master$", 5 | "^refs/heads/develop$", 6 | "^refs/heads/rel/v\\d+\\.\\d+" 7 | ], 8 | "version": "1.1" 9 | } 10 | --------------------------------------------------------------------------------