Repository: 0x7c13/Notepads Branch: master Commit: 8350f1ca8647 Files: 365 Total size: 4.2 MB Directory structure: gitextract_92diuyzb/ ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── RELEASE_TEMPLATE/ │ │ ├── changelog_config.json │ │ └── changelog_template.hbs │ ├── dependabot.yml │ ├── issue_label_bot.yaml │ └── workflows/ │ ├── csa-bulk-dismissal.yml │ └── main.yml ├── .gitignore ├── .whitesource ├── CI-CD_DOCUMENTATION.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── PRIVACY.md ├── README.md ├── azure-pipelines.yml └── src/ ├── .editorconfig ├── Notepads/ │ ├── App.xaml │ ├── App.xaml.cs │ ├── Brushes/ │ │ └── HostBackdropAcrylicBrush.cs │ ├── Commands/ │ │ ├── CommandHandlerResult.cs │ │ ├── ICommandHandler.cs │ │ ├── IKeyboardCommand.cs │ │ ├── IMouseCommand.cs │ │ ├── KeyboardCommand.cs │ │ ├── KeyboardCommandHandler.cs │ │ ├── MouseCommand.cs │ │ └── MouseCommandHandler.cs │ ├── Controls/ │ │ ├── Dialog/ │ │ │ ├── AppCloseSaveReminderDialog.cs │ │ │ ├── FileOpenErrorDialog.cs │ │ │ ├── FileRenameDialog.cs │ │ │ ├── FileSaveErrorDialog.cs │ │ │ ├── NotepadsDialog.cs │ │ │ ├── RevertAllChangesConfirmationDialog.cs │ │ │ ├── SessionCorruptionErrorDialog.cs │ │ │ └── SetCloseSaveReminderDialog.cs │ │ ├── DiffViewer/ │ │ │ ├── BrushFactory.cs │ │ │ ├── ISideBySideDiffViewer.cs │ │ │ ├── RichTextBlockDiffContext.cs │ │ │ ├── RichTextBlockDiffRenderer.cs │ │ │ ├── ScrollViewerSynchronizer.cs │ │ │ ├── SideBySideDiffViewer.xaml │ │ │ └── SideBySideDiffViewer.xaml.cs │ │ ├── FilePicker/ │ │ │ └── FilePickerFactory.cs │ │ ├── FindAndReplace/ │ │ │ ├── FindAndReplaceControl.xaml │ │ │ ├── FindAndReplaceControl.xaml.cs │ │ │ ├── FindAndReplaceEventArgs.cs │ │ │ ├── FindAndReplacePlaceHolder.xaml │ │ │ ├── FindAndReplaceTextBox.cs │ │ │ └── SearchContext.cs │ │ ├── GoTo/ │ │ │ ├── GoToControl.xaml │ │ │ ├── GoToControl.xaml.cs │ │ │ └── GoToEventArgs.cs │ │ ├── Markdown/ │ │ │ ├── MarkdownExtensionView.xaml │ │ │ └── MarkdownExtensionView.xaml.cs │ │ ├── Print/ │ │ │ ├── ContinuationPageFormat.xaml │ │ │ ├── ContinuationPageFormat.xaml.cs │ │ │ ├── PrintArgs.cs │ │ │ ├── PrintPageFormat.xaml │ │ │ └── PrintPageFormat.xaml.cs │ │ └── TextEditor/ │ │ ├── ITextEditor.cs │ │ ├── TextEditor.xaml │ │ ├── TextEditor.xaml.cs │ │ ├── TextEditorContextFlyout.cs │ │ ├── TextEditorCore.DateTime.cs │ │ ├── TextEditorCore.DuplicateText.cs │ │ ├── TextEditorCore.ExternalEventListener.cs │ │ ├── TextEditorCore.FindAndReplace.cs │ │ ├── TextEditorCore.FontSize.cs │ │ ├── TextEditorCore.Indentation.cs │ │ ├── TextEditorCore.JoinText.cs │ │ ├── TextEditorCore.LineHighlighter.cs │ │ ├── TextEditorCore.LineNumbers.cs │ │ ├── TextEditorCore.MoveText.cs │ │ ├── TextEditorCore.WebSearch.cs │ │ ├── TextEditorCore.cs │ │ ├── TextEditorCore.xaml │ │ └── TextEditorStateMetaData.cs │ ├── Core/ │ │ ├── INotepadsCore.cs │ │ ├── ISessionManager.cs │ │ ├── NotepadsCore.cs │ │ ├── SessionDataModels/ │ │ │ ├── NotepadsSessionData.cs │ │ │ └── TextEditorSessionData.cs │ │ ├── SessionManager.cs │ │ └── TabContextFlyout.cs │ ├── Extensions/ │ │ ├── DispatcherExtensions.cs │ │ ├── IContentPreviewExtension.cs │ │ ├── INotepadsExtensionProvider.cs │ │ ├── NotepadsExtensionProvider.cs │ │ ├── ScrollViewerExtensions.cs │ │ └── StringExtensions.cs │ ├── Models/ │ │ └── TextFile.cs │ ├── Notepads.csproj │ ├── Package.StoreAssociation.xml │ ├── Package.appxmanifest │ ├── Package.targets │ ├── Program.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ └── Default.rd.xml │ ├── Resource/ │ │ ├── CustomAppBarButtonStyle.xaml │ │ ├── CustomCheckBoxStyle.xaml │ │ ├── CustomNavigationViewItemStyle.xaml │ │ ├── CustomRadioButtonStyle.xaml │ │ ├── CustomSliderStyle.xaml │ │ ├── CustomSplitViewStyle.xaml │ │ ├── CustomToggleSwitchStyle.xaml │ │ ├── DismissButtonStyle.xaml │ │ ├── InAppNotificationNoDismissButton.xaml │ │ ├── MiddleClickScrolling-CursorType.res │ │ ├── Text Document.txt │ │ └── TransparentTextBoxStyle.xaml │ ├── Services/ │ │ ├── ActivationService.cs │ │ ├── AnalyticsService.cs │ │ ├── AppSettingsService.cs │ │ ├── FileExtensionProvider.cs │ │ ├── JumpListService.cs │ │ ├── LoggingService.cs │ │ ├── MRUService.cs │ │ ├── NotepadsProtocolService.cs │ │ ├── NotificationCenter.cs │ │ └── ThemeSettingsService.cs │ ├── Settings/ │ │ ├── ApplicationSettings.cs │ │ └── SettingsKey.cs │ ├── Strings/ │ │ ├── ar-YE/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── bg-BG/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── cs-CZ/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── de-CH/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── de-DE/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── en-US/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── es-ES/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── fi-FI/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── fr-FR/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── hi-IN/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── hr-HR/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── hu-HU/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── it-IT/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── ja-JP/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── ka-GE/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── ko-KR/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── nl-NL/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── or-IN/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── pl-PL/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── pt-BR/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── pt-PT/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── ru-RU/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── sr-Latn/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── sr-cyrl/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── tr-TR/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── uk-UA/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── vi-VN/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ ├── zh-CN/ │ │ │ ├── Manifest.resw │ │ │ ├── Resources.resw │ │ │ └── Settings.resw │ │ └── zh-TW/ │ │ ├── Manifest.resw │ │ ├── Resources.resw │ │ └── Settings.resw │ ├── Utilities/ │ │ ├── BrushUtility.cs │ │ ├── DialogManager.cs │ │ ├── Downloader.cs │ │ ├── EncodingUtility.cs │ │ ├── FileSystemUtility.cs │ │ ├── FileTypeUtility.cs │ │ ├── FontUtility.cs │ │ ├── FutureAccessListUtility.cs │ │ ├── LanguageUtility.cs │ │ ├── LineEndingUtility.cs │ │ ├── SearchEngineUtility.cs │ │ ├── SessionUtility.cs │ │ └── ThreadUtility.cs │ └── Views/ │ ├── MainPage/ │ │ ├── NotepadsMainPage.IO.cs │ │ ├── NotepadsMainPage.MainMenu.cs │ │ ├── NotepadsMainPage.Notification.cs │ │ ├── NotepadsMainPage.StatusBar.cs │ │ ├── NotepadsMainPage.Theme.cs │ │ ├── NotepadsMainPage.ViewModes.cs │ │ ├── NotepadsMainPage.xaml │ │ └── NotepadsMainPage.xaml.cs │ └── Settings/ │ ├── AboutPage.xaml │ ├── AboutPage.xaml.cs │ ├── AdvancedSettingsPage.xaml │ ├── AdvancedSettingsPage.xaml.cs │ ├── PersonalizationSettingsPage.xaml │ ├── PersonalizationSettingsPage.xaml.cs │ ├── SettingsPage.xaml │ ├── SettingsPage.xaml.cs │ ├── SettingsPanel.xaml │ ├── SettingsPanel.xaml.cs │ ├── TextAndEditorSettingsPage.xaml │ └── TextAndEditorSettingsPage.xaml.cs ├── Notepads.Controls/ │ ├── DropShadowPanel/ │ │ ├── DropShadowPanel.Properties.cs │ │ ├── DropShadowPanel.cs │ │ └── DropShadowPanel.xaml │ ├── GridSplitter/ │ │ ├── GridSplitter.Data.cs │ │ ├── GridSplitter.Events.cs │ │ ├── GridSplitter.Helper.cs │ │ ├── GridSplitter.Options.cs │ │ ├── GridSplitter.cs │ │ ├── GridSplitter.xaml │ │ └── GripperHoverWrapper.cs │ ├── Helpers/ │ │ ├── DispatcherQueueHelper.cs │ │ └── ThemeListener.cs │ ├── InAppNotification/ │ │ ├── InAppNotification.AttachedProperties.cs │ │ ├── InAppNotification.Constants.cs │ │ ├── InAppNotification.Events.cs │ │ ├── InAppNotification.Properties.cs │ │ ├── InAppNotification.cs │ │ ├── InAppNotification.xaml │ │ ├── InAppNotificationClosedEventArgs.cs │ │ ├── InAppNotificationClosingEventArgs.cs │ │ ├── InAppNotificationDismissKind.cs │ │ ├── InAppNotificationOpeningEventArgs.cs │ │ ├── NotificationOptions.cs │ │ ├── StackMode.cs │ │ └── Styles/ │ │ └── MSEdgeNotificationStyle.xaml │ ├── MarkdownTextBlock/ │ │ ├── CodeBlockResolvingEventArgs.cs │ │ ├── ImageResolvingEventArgs.cs │ │ ├── LinkClickedEventArgs.cs │ │ ├── Markdown/ │ │ │ ├── Blocks/ │ │ │ │ ├── CodeBlock.cs │ │ │ │ ├── HeaderBlock.cs │ │ │ │ ├── HorizontalRuleBlock.cs │ │ │ │ ├── LinkReferenceBlock.cs │ │ │ │ ├── List/ │ │ │ │ │ ├── ListItemBlock.cs │ │ │ │ │ ├── ListItemBuilder.cs │ │ │ │ │ ├── ListItemPreamble.cs │ │ │ │ │ └── NestedListInfo.cs │ │ │ │ ├── ListBlock.cs │ │ │ │ ├── ParagraphBlock.cs │ │ │ │ ├── QuoteBlock.cs │ │ │ │ ├── TableBlock.cs │ │ │ │ └── YamlHeaderBlock.cs │ │ │ ├── Core/ │ │ │ │ ├── IParser.cs │ │ │ │ ├── ParseHelpers.cs │ │ │ │ ├── SchemaBase.cs │ │ │ │ └── StringValueAttribute.cs │ │ │ ├── Enums/ │ │ │ │ ├── ColumnAlignment.cs │ │ │ │ ├── HyperlinkType.cs │ │ │ │ ├── InlineParseMethod.cs │ │ │ │ ├── ListStyle.cs │ │ │ │ ├── MarkdownBlockType.cs │ │ │ │ └── MarkdownInlineType.cs │ │ │ ├── Helpers/ │ │ │ │ ├── Common.cs │ │ │ │ ├── DebuggingReporter.cs │ │ │ │ ├── InlineParseResult.cs │ │ │ │ ├── InlineTripCharHelper.cs │ │ │ │ └── LineInfo.cs │ │ │ ├── Inlines/ │ │ │ │ ├── BoldItalicTextInline.cs │ │ │ │ ├── BoldTextInline.cs │ │ │ │ ├── CodeInline.cs │ │ │ │ ├── CommentInline.cs │ │ │ │ ├── EmojiInline.EmojiCodes.cs │ │ │ │ ├── EmojiInline.cs │ │ │ │ ├── HyperlinkInline.cs │ │ │ │ ├── IInlineContainer.cs │ │ │ │ ├── IInlineLeaf.cs │ │ │ │ ├── ILinkElement.cs │ │ │ │ ├── ImageInline.cs │ │ │ │ ├── ItalicTextInline.cs │ │ │ │ ├── LinkAnchorInline.cs │ │ │ │ ├── MarkdownLinkInline.cs │ │ │ │ ├── StrikethroughTextInline.cs │ │ │ │ ├── SubscriptTextInline.cs │ │ │ │ ├── SuperscriptTextInline.cs │ │ │ │ └── TextRunInline.cs │ │ │ ├── MarkdownBlock.cs │ │ │ ├── MarkdownDocument.cs │ │ │ ├── MarkdownElement.cs │ │ │ ├── MarkdownInline.cs │ │ │ └── Render/ │ │ │ ├── ICodeBlockResolver.cs │ │ │ ├── IImageResolver.cs │ │ │ ├── ILinkRegister.cs │ │ │ ├── IRenderContext.cs │ │ │ ├── InlineRenderContext.cs │ │ │ ├── MarkdownRenderer.Blocks.cs │ │ │ ├── MarkdownRenderer.Dimensions.cs │ │ │ ├── MarkdownRenderer.Inlines.cs │ │ │ ├── MarkdownRenderer.Properties.cs │ │ │ ├── MarkdownRenderer.cs │ │ │ ├── MarkdownRendererBase.Blocks.cs │ │ │ ├── MarkdownRendererBase.Inlines.cs │ │ │ ├── MarkdownRendererBase.cs │ │ │ ├── MarkdownTable.cs │ │ │ ├── RenderContext.cs │ │ │ ├── RenderContextIncorrectException.cs │ │ │ └── UIElementCollectionRenderContext.cs │ │ ├── MarkdownRenderedEventArgs.cs │ │ ├── MarkdownTextBlock.Dimensions.cs │ │ ├── MarkdownTextBlock.Events.cs │ │ ├── MarkdownTextBlock.Methods.cs │ │ ├── MarkdownTextBlock.Properties.cs │ │ ├── MarkdownTextBlock.cs │ │ └── MarkdownTextBlock.xaml │ ├── Notepads.Controls.csproj │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ └── Notepads.Controls.rd.xml │ ├── SetsView/ │ │ ├── SetClosingEventArgs.cs │ │ ├── SetDraggedOutsideEventArgs.cs │ │ ├── SetSelectedEventArgs.cs │ │ ├── SetsView.HeaderLayout.cs │ │ ├── SetsView.ItemSources.cs │ │ ├── SetsView.Properties.cs │ │ ├── SetsView.cs │ │ ├── SetsView.xaml │ │ ├── SetsViewItem.Properties.cs │ │ ├── SetsViewItem.cs │ │ └── SetsWidthMode.cs │ └── Themes/ │ └── Generic.xaml └── Notepads.sln ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ # Set the default behavior, in case people don't have core.autocrlf set. * text=auto # Declare files that will always have CRLF line endings on checkout. *.cs text eol=crlf *.xaml text eol=crlf *.resw text eol=crlf *.csproj text eol=crlf *.sln text eol=crlf # Denote all files that are truly binary and should not be modified. *.png binary *.jpg binary ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: 0x7c13 patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: jackieliu tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: paypal.me/jackil ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: "[Bug]" labels: '' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior. **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. Windows 10 1809 17763.593] - Version [e.g. v0.9.3.0] **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: "[Feature request]" labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ## PR Type What kind of change does this PR introduce? ## Other information ================================================ FILE: .github/RELEASE_TEMPLATE/changelog_config.json ================================================ { "conventionalCommitsParserOptions": { "revertPattern": "/^(?:Revert|revert:)\\s\"?([\\s\\S]+?)\"?\\s*This reverts commit (\\w*)\\./i", "issuePrefixes": [ "#", "OLDARCH-" ] }, "handleBarsOptions": { "setupFile": null, "template": ".github/RELEASE_TEMPLATE/changelog_template.hbs", "compileOptions": { "noEscape": true } }, "breakingChangesPattern": "/^breaking\\s+change$/gim", "hostname": "https://github.com" } ================================================ FILE: .github/RELEASE_TEMPLATE/changelog_template.hbs ================================================ {{#with release}} ## [{{name}}]({{href}}) {{/with}} {{#commit-list commits heading='### 💥 Breaking Changes' breaking=true }} - {{#if scope}} **{{scope}}:** {{/if}}{{subject}} ([`{{shorthash}}`]({{html_url}})) {{/commit-list}} {{#commit-list commits heading='### ✨ Features' type='feat' excludeBreaking=true}} - {{#if scope}} **{{scope}}:** {{/if}}{{subject}} ([`{{shorthash}}`]({{html_url}})) {{/commit-list}} {{#commit-list commits heading='### 🐛 Fixes' type='fix' excludeBreaking=true }} - {{#if scope}} **{{scope}}:** {{/if}}{{subject}} ([`{{shorthash}}`]({{html_url}})) {{/commit-list}} {{#commit-list commits heading='### 🔥 Refactorings' type='refactor' excludeBreaking=true }} - {{#if scope}} **{{scope}}:** {{/if}}{{subject}} ([`{{shorthash}}`]({{html_url}})) {{/commit-list}} {{#commit-list commits heading='### 🐎 Performance Improvements' type='perf' excludeBreaking=true }} - {{#if scope}} **{{scope}}:** {{/if}}{{subject}} ([`{{shorthash}}`]({{html_url}})) {{/commit-list}} {{#commit-list commits heading='### 🛠 Maintenance' types='chore,ci' excludeBreaking=true }} - {{#if scope}} **{{scope}}:** {{/if}}{{subject}} ([`{{shorthash}}`]({{html_url}})) {{/commit-list}} {{#commit-list commits heading='### ✅ Tests' type='test' excludeBreaking=true }} - {{#if scope}} **{{scope}}:** {{/if}}{{subject}} ([`{{shorthash}}`]({{html_url}})) {{/commit-list}} {{#commit-list commits heading='### 📚 Documentation' type='doc,docs' excludeBreaking=true }} - {{#if scope}} **{{scope}}:** {{/if}}{{subject}} ([`{{shorthash}}`]({{html_url}})) {{/commit-list}} {{#commit-list commits heading='### 💄 Style' type='style' excludeBreaking=true }} - {{#if scope}} **{{scope}}:** {{/if}}{{subject}} ([`{{shorthash}}`]({{html_url}})) {{/commit-list}} {{#commit-list commits heading='### 📢 Translations' type='lang,trans' excludeBreaking=true }} - {{#if scope}} **{{scope}}:** {{/if}}{{subject}} ([`{{shorthash}}`]({{html_url}})) {{/commit-list}} ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "github-actions" # default location of `.github/workflows` directory: "/" schedule: interval: "weekly" commit-message: prefix: 'action-deps: ' - package-ecosystem: "nuget" # location of package manifests directory: "/src/Notepads" schedule: interval: "daily" commit-message: prefix: 'nuget-deps: ' # Built with ❤ by [Pipeline Foundation](https://pipeline.foundation) ================================================ FILE: .github/issue_label_bot.yaml ================================================ label-alias: bug: 'bug' feature_request: 'enhancement' question: 'question' ================================================ FILE: .github/workflows/csa-bulk-dismissal.yml ================================================ name: Code scanning alerts bulk dismissal on: workflow_run: workflows: [ "Notepads CI/CD Pipeline" ] types: - completed workflow_dispatch: inputs: type: description: Type of filter to use ("path" for using path and "desc" for using description) required: true default: 'path' reason: description: Reason for dismissal ("fp" for "false positive", "wf" for "won't fix" and "ut" for "used in tests") required: true default: 'wf' jobs: setup: runs-on: windows-latest outputs: matrix: ${{ steps.set_filter_matrix.outputs.matrix }} steps: - name: Setup filter matrix id: set_filter_matrix shell: pwsh run: | $FILTER_TYPE = $env:FILTER_TYPE if ( !( $env:FILTER_TYPE -ieq 'path' ) -And !( $env:FILTER_TYPE -ieq 'desc' ) ) { $FILTER_TYPE = 'path' } switch ( $env:REASON ) { fp { $REASON = "false positive" } wf { $REASON = "won't fix" } ut { $REASON = "used in tests" } default { $REASON = "won't fix" } } if ( $FILTER_TYPE -ieq 'path' ) { $MATRIX = @{ include = @( @{ filter = "*/obj/*" } ) } } elseif ( $FILTER_TYPE -ieq 'desc' ) { $MATRIX = @{ include = @( @{ filter = "Calls to unmanaged code" }, @{ filter = "Unmanaged code" } ) } } else { throw "Invalid filter type argument" } $MATRIX.include | Foreach-Object { $_.Add('type',"$FILTER_TYPE") $_.Add('reason',"$REASON") } echo "::set-output name=matrix::$($MATRIX | ConvertTo-Json -depth 32 -Compress)" env: FILTER_TYPE: ${{ github.event.inputs.type }} REASON: ${{ github.event.inputs.reason }} dismiss-alerts: name: Dismiss alerts needs: setup runs-on: windows-latest strategy: matrix: ${{ fromJson(needs.setup.outputs.matrix) }} env: # Settings OWNER: ${{ github.repository_owner }} # verbatim from URL PROJECT_NAME: ${{ github.event.repository.name }} # verbatim from URL ACCESS_TOKEN: ${{ secrets.CSA_ACCESS_TOKEN }} # requires security_events read/write permissions DISMISS_REASON: ${{ matrix.reason }} # "false positive", "won't fix" or "used in tests". ALERTS_PER_PAGE: 100 # maximum is 100 FILTER: ${{ matrix.filter }} FILTER_TYPE: ${{ matrix.type }} steps: - name: Run automation id: run_automation shell: pwsh run: | $HEADERS = @{ Authorization = 'Basic {0}' -f [System.Convert]::ToBase64String([char[]]"$($env:OWNER):$($env:ACCESS_TOKEN)") Accept = 'application/vnd.github.v3+json' } $page = 1 $FETCH_URL = "https://api.github.com/repos/$env:OWNER/$env:PROJECT_NAME/code-scanning/alerts?state=open&page={0}&per_page=$env:ALERTS_PER_PAGE" $LIST_OF_ALERTS = Invoke-RestMethod -Method Get -Headers $HEADERS -Uri $($FETCH_URL -f $page) while ( $LIST_OF_ALERTS -ne $null ) { if ( $env:FILTER_TYPE -ieq 'path' ) { $MATCHES += $($LIST_OF_ALERTS | Where-Object { $_.most_recent_instance.location.path -like "$env:FILTER" }) } else { $MATCHES += $($LIST_OF_ALERTS | Where-Object { $_.rule.description -like "$env:FILTER" }) } $page += 1 $LIST_OF_ALERTS = Invoke-RestMethod -Method Get -Headers $HEADERS -Uri $($FETCH_URL -f $page) } $ALERT_URL = "https://api.github.com/repos/$env:OWNER/$env:PROJECT_NAME/code-scanning/alerts/{0}" $BODY = @{ state = 'dismissed' dismissed_reason = "$env:DISMISS_REASON" } | ConvertTo-Json foreach ($index in $MATCHES.number) { Invoke-RestMethod -Method Patch -Headers $HEADERS -Uri $($ALERT_URL -f $index) -Body $BODY } # Built with ❤ by [Pipeline Foundation](https://pipeline.foundation) ================================================ FILE: .github/workflows/main.yml ================================================ name: Notepads CI/CD Pipeline on: push: #paths-ignore: #- '**.md' #- 'ScreenShots/**' #- '.whitesource' #- 'azure-pipelines.yml' #- '.github/**' #- '!.github/workflows/main.yml' branches-ignore: # PRs made by bots trigger both 'push' and 'pull_request' event, ignore 'push' event in that case - 'dependabot**' - 'imgbot**' tags-ignore: - '**' pull_request: paths-ignore: - '**.md' - 'ScreenShots/**' - '.whitesource' - 'azure-pipelines.yml' - '.github/**' - '!.github/workflows/main.yml' workflow_dispatch: inputs: param: description: Optional parameter for additional actions # Type '(major|maj) (realease|rel)' or '(minor|min) (realease|rel)' or release for major,miner,patch release respectively # Or explicitly provide version number to create release with that version required: false schedule: - cron: '0 8 * * *' jobs: setup: runs-on: windows-latest outputs: matrix: ${{ steps.set_matrix.outputs.matrix }} steps: - name: Setup strategy matrix id: set_matrix shell: pwsh run: | $MATRIX = @{ include = @( [ordered]@{ configuration= "Debug" appxBundlePlatforms = "x86|x64" oldVersion = "" newVersion = "" debug = $true runCodeqlAnalysis = $false runSonarCloudScan = $false }, [ordered]@{ configuration= "Release" appxBundlePlatforms= "x86|x64|ARM64" oldVersion = "" newVersion = "" debug = $true runCodeqlAnalysis= $false runSonarCloudScan= $false }, [ordered]@{ configuration= "Production" appxBundlePlatforms= "x86|x64|ARM64" oldVersion = "" newVersion = "" debug = $true runCodeqlAnalysis= $false runSonarCloudScan= $false } ) } if ( ( $env:GITHUB_EVENT -eq 'pull_request' ) ` -or ( $env:GITHUB_EVENT -eq 'schedule' ) ` -or ( $env:FORK -eq 'true' ) ) { $MATRIX.include | Foreach-Object { $_.runSonarCloudScan = $false } } if ( ( $env:GITHUB_EVENT -ne 'push' ) ` -and ( $env:GITHUB_EVENT -ne 'pull_request' ) ) { $MATRIX.include = @($MATRIX.include | Where-Object { $_.configuration -eq "$env:RELEASE_CONFIGURATION" }) if ( ( $env:GITHUB_EVENT -eq 'workflow_dispatch' ) ` -and ( $env:GITHUB_REF -eq 'refs/heads/master' ) ) { $FETCH_URL = "https://api.github.com/repos/$env:GIT_REPOSITORY/tags?per_page=1" $OLD_VER = [System.Version]::Parse($(Invoke-RestMethod -Method Get -Uri $FETCH_URL).name -replace 'v') [System.Int32[]]$VER_INPUT = $($env:PARAM -replace '[a-zA-Z]| ').Split('.') if ( ( $VER_INPUT.Count -gt 1 ) -or ( $VER_INPUT[0] -gt 0 ) ) { $NEW_VER = [System.Version]::new($VER_INPUT[0],` (if ( $VER_INPUT.Count -ge 1 ) { $VER_INPUT[1] } else { 0 }),` (if ( $VER_INPUT.Count -ge 2 ) { $VER_INPUT[2] } else { 0 }),` (if ( $VER_INPUT.Count -ge 3 ) { $VER_INPUT[3] } else { 0 })) } elseif ( $env:PARAM -match 'rel' ) { if ( $env:PARAM -match 'maj' ) { $NEW_VER = [System.Version]::new($OLD_VER.Major + 1, 0, 0, 0) } elseif ( $env:PARAM -match 'min' ) { $NEW_VER = [System.Version]::new($OLD_VER.Major, $OLD_VER.Minor + 1, 0, 0) } else { $NEW_VER = [System.Version]::new($OLD_VER.Major, $OLD_VER.Minor, $OLD_VER.Build + 1, 0) } } if ( ![System.String]::IsNullOrEmpty($OLD_VER) ` -and ![System.String]::IsNullOrEmpty($NEW_VER) ` -and ( $NEW_VER -gt $OLD_VER ) ) { $MATRIX.include | Foreach-Object { $_.oldVersion = $OLD_VER.ToString() } $MATRIX.include | Foreach-Object { $_.newVersion = $NEW_VER.ToString() } } $MATRIX.include | Foreach-Object { $_.runCodeqlAnalysis = $false } $MATRIX.include | Foreach-Object { if ( $_.configuration -eq "$env:RELEASE_CONFIGURATION" ) { $_.release = $true } } } else { $MATRIX.include | Foreach-Object { $_.appxBundlePlatforms = 'x64' } if ( $env:GITHUB_EVENT -ne 'schedule' ) { $MATRIX.include | Foreach-Object { $_.runCodeqlAnalysis = $false } } } } echo "::set-output name=matrix::$($MATRIX | ConvertTo-Json -depth 32 -Compress)" env: FORK: ${{ github.event.repository.fork }} PARAM: ${{ github.event.inputs.param }} GITHUB_REF: ${{ github.ref }} GITHUB_EVENT: ${{ github.event_name }} RELEASE_CONFIGURATION: Production ci: needs: setup runs-on: windows-latest strategy: matrix: ${{ fromJson(needs.setup.outputs.matrix) }} outputs: old_version: ${{ matrix.oldVersion }} new_version: ${{ matrix.newVersion }} env: SOLUTION_NAME: src\Notepads.sln CONFIGURATION: ${{ matrix.configuration }} DEFAULT_DIR: ${{ github.workspace }} steps: - if: matrix.runSonarCloudScan name: Set up JDK 11 id: Setup_JDK uses: actions/setup-java@v5 with: java-version: 1.11 - name: Setup MSBuild id: setup_msbuild uses: microsoft/setup-msbuild@v2 - name: Setup NuGet id: setup-nuget uses: NuGet/setup-nuget@v2.0.1 - name: Checkout repository id: checkout_repo uses: actions/checkout@v5 with: fetch-depth: 50 token: ${{ secrets.GITHUB_TOKEN }} # Due to the insufficient memory allocated by default, CodeQL sometimes requires more to be manually allocated - if: matrix.runCodeqlAnalysis name: Configure Pagefile id: config_pagefile uses: al-cheb/configure-pagefile-action@v1.4 with: minimum-size: 8GB maximum-size: 10GB - if: matrix.newVersion != '' name: Bump GitHub tag and Update manifest id: tag_manifest_generator shell: pwsh run: | git config --global user.name $env:GIT_USER_NAME git config --global user.email $env:GIT_USER_EMAIL git tag -a -m "$env:NEW_VERSION_TAG" $env:NEW_VERSION_TAG git push --follow-tags $xml = [xml](Get-Content $env:APPXMANIFEST_PATH) $xml.Package.Identity.Version = $env:NEW_VERSION $xml.save($env:APPXMANIFEST_PATH) env: GIT_USER_NAME: ${{ secrets.GIT_USER_NAME }} GIT_USER_EMAIL: ${{ secrets.GIT_USER_EMAIL }} APPXMANIFEST_PATH: src\Notepads\Package.appxmanifest NEW_VERSION: ${{ matrix.newVersion }} NEW_VERSION_TAG: v${{ matrix.newVersion }} - if: matrix.runSonarCloudScan name: Cache SonarCloud packages id: cache_sonar_packages uses: actions/cache@v4.3.0 with: path: ~\sonar\cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - if: matrix.runSonarCloudScan name: Cache SonarCloud scanner id: cache_sonar_scanner uses: actions/cache@v4.3.0 with: path: .\.sonar\scanner key: ${{ runner.os }}-sonar-scanner restore-keys: ${{ runner.os }}-sonar-scanner - if: matrix.runSonarCloudScan && steps.cache_sonar_scanner.outputs.cache-hit != 'true' name: Install SonarCloud scanner id: install_sonar_scanner shell: pwsh run: | New-Item -Path .\.sonar\scanner -ItemType Directory dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner - if: matrix.runSonarCloudScan name: Initialize SonarCloud scanner id: init_sonar_scanner shell: pwsh run: | $LOWERCASE_REPOSITORY_NAME = "${{ github.event.repository.name }}".ToLower() .\.sonar\scanner\dotnet-sonarscanner begin ` /k:"${{ github.repository_owner }}_${{ github.event.repository.name }}" ` /o:"$LOWERCASE_REPOSITORY_NAME" ` /d:sonar.login="$env:SONAR_TOKEN" ` /d:sonar.host.url="https://sonarcloud.io" env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - if: matrix.newVersion != '' name: Create and validate PFX certificate for AppxBundle id: create_validate_pfx_cert shell: pwsh run: | $TARGET_FILE = "$env:DEFAULT_DIR\cert.pfx" $FROM_BASE64_STR = [System.Convert]::FromBase64String($env:BASE64_STR) [System.IO.File]::WriteAllBytes($TARGET_FILE, $FROM_BASE64_STR) $FILE_STREAM = [System.IO.File]::OpenRead($TARGET_FILE) $FILE_STREAM.Position = 0 $SHA256 = [System.Security.Cryptography.SHA256]::Create() $HASH_BUILDER = [System.Text.StringBuilder]::new() $SHA256.ComputeHash($FILE_STREAM) | ForEach-Object { $HASH_BUILDER.Append($_.ToString("x2")) } if ( $HASH_BUILDER.ToString() -cne $env:SHA256_HASH ) { throw [System.Exception]::new("Created certificate hash $($HASH_BUILDER.ToString()) $( )doesn't match provided hash $($env:SHA256_HASH)") } env: BASE64_STR: ${{ secrets.PACKAGE_CERTIFICATE_BASE64 }} SHA256_HASH: ${{ secrets.PACKAGE_CERTIFICATE_SHA256 }} - name: Restore the application id: restore_application shell: pwsh run: | msbuild $env:SOLUTION_NAME /t:Restore nuget restore $env:SOLUTION_NAME - if: matrix.runCodeqlAnalysis name: Initialize CodeQL id: init_codeql uses: github/codeql-action/init@v3 with: queries: security-and-quality languages: csharp - name: Build and generate bundles id: build_app shell: pwsh run: | msbuild $env:SOLUTION_NAME ` /p:Platform=$env:PLATFORM ` /p:Configuration=$env:CONFIGURATION ` /p:UapAppxPackageBuildMode=$env:UAP_APPX_PACKAGE_BUILD_MODE ` /p:AppxBundle=$env:APPX_BUNDLE ` /p:AppxPackageSigningEnabled=$env:APPX_PACKAGE_SIGNING_ENABLED ` /p:AppxBundlePlatforms=$env:APPX_BUNDLE_PLATFORMS ` /p:AppxPackageDir=$env:ARTIFACTS_DIR ` /p:PackageCertificateKeyFile=$env:PACKAGE_CERTIFICATE_KEYFILE ` /p:PackageCertificatePassword=$env:PACKAGE_CERTIFICATE_PASSWORD env: PLATFORM: x64 UAP_APPX_PACKAGE_BUILD_MODE: StoreUpload APPX_BUNDLE: Always APPX_PACKAGE_SIGNING_ENABLED: ${{ matrix.newVersion != '' }} APPX_BUNDLE_PLATFORMS: ${{ matrix.appxBundlePlatforms }} ARTIFACTS_DIR: ${{ github.workspace }}\Artifacts PACKAGE_CERTIFICATE_KEYFILE: ${{ github.workspace }}\cert.pfx PACKAGE_CERTIFICATE_PASSWORD: ${{ secrets.PACKAGE_CERTIFICATE_PWD }} APP_CENTER_SECRET: ${{ secrets.APP_CENTER_SECRET }} - if: matrix.debug && !contains( matrix.appxBundlePlatforms, 'arm64' ) name: Test ARM build in debug configuration id: build_app_arm_debug shell: pwsh run: | msbuild $env:SOLUTION_NAME ` /p:Platform=$env:PLATFORM ` /p:Configuration=$env:CONFIGURATION ` /p:UapAppxPackageBuildMode=$env:UAP_APPX_PACKAGE_BUILD_MODE ` /p:AppxBundle=$env:APPX_BUNDLE ` /p:AppxBundlePlatforms=$env:APPX_BUNDLE_PLATFORMS env: PLATFORM: ARM64 UAP_APPX_PACKAGE_BUILD_MODE: StoreUpload APPX_BUNDLE: Always APPX_BUNDLE_PLATFORMS: ARM64 - if: matrix.runCodeqlAnalysis name: Perform CodeQL Analysis id: analyze_codeql uses: github/codeql-action/analyze@v3 continue-on-error: true - if: matrix.runSonarCloudScan name: Send SonarCloud results id: send_sonar_results shell: pwsh run: | .\.sonar\scanner\dotnet-sonarscanner end ` /d:sonar.login="$env:SONAR_TOKEN" env: GITHUB_TOKEN: ${{ secrets.SONAR_GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - if: matrix.newVersion != '' name: Upload build artifacts id: upload_artifacts uses: actions/upload-artifact@v4 with: name: Build artifacts path: Artifacts/ cd: # This job will execute when the workflow is triggered on a 'workflow_dispatch' event, # the target branch is 'master' and required parameter provided for release. if: needs.ci.outputs.new_version != '' needs: [ setup, ci ] runs-on: windows-latest env: OLD_VERSION: ${{ needs.ci.outputs.old_version }} NEW_VERSION: ${{ needs.ci.outputs.new_version }} steps: - name: Checkout repository id: checkout_repo uses: actions/checkout@v5 - name: Download and extract MSIX package id: dl_package_artifact uses: actions/download-artifact@v6 with: name: Build artifacts path: Artifacts/ - name: Create deployment payload id: create_notepads_zip shell: pwsh run: | Get-ChildItem -Filter *Production* -Recurse | Rename-Item -NewName { $_.name -replace "_Production|_Test",'' } Compress-Archive -Path "Notepads_$($env:NEW_VERSION)\*" ` -DestinationPath "Notepads_$($env:NEW_VERSION)\Notepads_$($env:NEW_VERSION)_x86_x64_ARM64.zip" working-directory: ./Artifacts - name: Generate changelog id: generate_changlog uses: mrchief/universal-changelog-action@v1.3.2 with: previousReleaseTagNameOrSha: v${{ env.OLD_VERSION }} nextReleaseTagName: v${{ env.NEW_VERSION }} nextReleaseName: v${{ env.NEW_VERSION }} configFilePath: .github/RELEASE_TEMPLATE/changelog_config.json - name: Create and publish release id: create_release uses: ncipollo/release-action@v1.20.0 with: allowUpdates: true replacesArtifacts: true tag: v${{ env.NEW_VERSION }} name: Notepads v${{ env.NEW_VERSION }} body: ${{ steps.generate_changlog.outputs.changelog }} token: ${{ secrets.GITHUB_TOKEN }} artifacts: Artifacts/Notepads_${{ env.NEW_VERSION }}/Notepads_${{ env.NEW_VERSION }}_x86_x64_ARM64.msixbundle Artifacts/Notepads_${{ env.NEW_VERSION }}/Notepads_${{ env.NEW_VERSION }}_x86_x64_ARM64.zip # - name: Publish to Windows Store # id: publish_to_store # uses: isaacrlevin/windows-store-action@1.0 # with: # tenant-id: ${{ secrets.AZURE_AD_TENANT_ID }} # client-id: ${{ secrets.AZURE_AD_APPLICATION_CLIENT_ID }} # client-secret: ${{ secrets.AZURE_AD_APPLICATION_SECRET }} # app-id: ${{ secrets.STORE_APP_ID }} # package-path: "${{ github.workspace }}/Artifacts/" # Built with ❤ by [Pipeline Foundation](https://pipeline.foundation) ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ _pkginfo.txt *.appx # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- Backup*.rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # JetBrains Rider .idea/ *.sln.iml # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb # Logs and databases # ###################### *.log *.sql *.sqlite # OS generated files # ###################### .DS_Store .DS_Store? ._* .Spotlight-V100 .Trashes ehthumbs.db Thumbs.db ================================================ FILE: .whitesource ================================================ { "checkRunSettings": { "vulnerableCheckRunConclusionLevel": "failure" }, "issueSettings": { "minSeverityLevel": "LOW" } } ================================================ FILE: CI-CD_DOCUMENTATION.md ================================================ # Notepads CI/CD documentation - after merging the PR, the first run of the "Notepads CI/CD Pipeline" workflow will not complete successfully, because it requires specific setup explained in this documentation. The two other workflows "CodeQL Analysis" and "Build", should complete successfully. ## 1. Set up SonarCloud ### SonarCloud is a cloud-based code quality and security service #### Create SonarCloud project - Go to https://sonarcloud.io/ - Click the "Log in" button and create a new account or connect with GitHub account (recommended) - At the top right corner click the "+" sign - From the dropdown select "Create new Organization" - Click the "Choose an organization on GitHub" button - Select an account for the organization setup - On Repository Access select "Only select repositories" and select the project and click the "Save" button - On the "Create organization page" don't change the Key and click "Continue" - Select the Free plan then click the "Create Organization" button to finalize the creation of the Organization #### Configure SonarCloud project - At the top right corner click the "+" sign and select "Analyze new project" - Select the project and click the "Set Up" button in the box on the right - Under "Choose your analysis method" click "With GitHub Actions" and **keep the following page open** - [Create a new PAT with **repo_deployment** and **read:packages** permissions](#7-how-to-create-a-pat) and copy the value of the generated token - In the project's GitHub repository, go to the **Settings** tab -> Secrets - Click on **New Repository secret** and create a new secret with the name **SONAR_GITHUB_TOKEN** and the token you just copied as the value - Create another secret with the two values from the SonarCloud page you kept open, which you can close after completing this step ![SonarCloud_1](ScreenShots/CI-CD_DOCUMENTATION/SonarCloud_1.png) - [Run the "Notepads CI/CD Pipeline" workflow manually](#2-run-workflow-manually) #### Set Quality Gate - After the "Notepads CI/CD Pipeline" workflow has executed successfully, go to https://sonarcloud.io/projects and click on the project - In the alert bar above the results, click the "Set new code definition" button and select "Previous version" (notice the "New Code definition has been updated" alert at the top) - The Quality Gate will become active as soon as the next SonarCloud scan completes successfully
## 2. Run workflow manually Once you've set up all the steps above correctly, you should be able to successfully complete a manual execution of the "Notepads CI/CD Pipeline" workflow. 1. Go to the project's GitHub repository and click on the **Actions** tab 2. From the "Workflows" list on the left, click on "Notepads CI/CD Pipeline" 3. On the right, next to the "This workflow has a workflow_dispatch event trigger" label, click on the "Run workflow" dropdown, make sure the default branch is selected (if not manually changed, should be main or master) in the "Use workflow from" dropdown and click the "Run workflow" button 4. You can optionally fill the argument textbox with "release" to trigger [GitHub Release](#github_release) and [Store Upload](#store_upload) ![Actions_workflow_dispatch](ScreenShots/CI-CD_DOCUMENTATION/Actions_workflow_dispatch.png) 5. Once the workflow run has completed successfully, move on to the next step of the documentation NOTE: **screenshots are only exemplary**
## 3. Set up Dependabot Dependabot is a GitHub native security tool that goes through the dependencies in the project and creates alerts, and PRs with updates when a new and/or non-vulnerable version is found. - for PRs with version updates, this pipeline comes pre-configured for all current dependency sources in the project, so at "Insights" tab -> "Dependency graph" -> "Dependabot", you should be able to see all tracked sources of dependencies, when they have been checked last and view a full log of the last check ![Dependabot_tab](ScreenShots/CI-CD_DOCUMENTATION/Dependabot_tab.png) ![Dependabot_log_page](ScreenShots/CI-CD_DOCUMENTATION/Dependabot_log_page.png) ### Set up security alerts and updates ##### - GitHub, through Dependabot, also natively offers a security check for vulnerable dependencies 1. Go to "Settings" tab of the repo 2. Go to "Security & analysis" section 3. Click "Enable" for both "Dependabot alerts" and "Dependabot security updates" - By enabling "Dependabot alerts", you would be notified for any vulnerable dependencies in the project. At "Security" tab -> "Dependabot alerts", you can manage all alerts. By clicking on an alert, you would be able to see a detailed explanation of the vulnerability and a viable solution. ![Dependabot_alerts_page](ScreenShots/CI-CD_DOCUMENTATION/Dependabot_alerts_page.png) ![Dependabot_alert_page](ScreenShots/CI-CD_DOCUMENTATION/Dependabot_alert_page.png) - By enabling "Dependabot security updates", you authorize Dependabot to create PRs specifically for **security updates** ![Dependabot_PRs](ScreenShots/CI-CD_DOCUMENTATION/Dependabot_PRs.png) ### Set up Dependency graph ##### - The "Dependency graph" option should be enabled by default for all public repos, but in case it isn't: 1. Go to "Settings" tab of the repo 2. Go to "Security&Analysis" section 3. Click "Enable" for the "Dependency graph" option - this option enables the "Insights" tab -> "Dependency graph" section -> "Dependencies" tab, in which all the dependencies for the project are listed, under the different manifests they are included in ![Dependabot_dependency_graph](ScreenShots/CI-CD_DOCUMENTATION/Dependabot_dependency_graph.png) NOTE: **screenshots are only exemplary**
## 4. CodeQL CodeQL is GitHub's own industry-leading semantic code analysis engine. CodeQL requires no setup, because it comes fully pre-configured by us. To activate it and see its results, only a push commit or a merge of a PR to the default branch of the repository, is required. We've also configured CodeQL to run on schedule, so every day at 8:00AM UTC, it automatically scans the code. - you can see the results here at **Security** tab -> **Code scanning alerts** -> **CodeQL**: ![CodeQL_results](ScreenShots/CI-CD_DOCUMENTATION/CodeQL_results.png) - on the page of each result, you can see an explanation of what the problem is and also one or more solutions: ![CodeQL_alert_page](ScreenShots/CI-CD_DOCUMENTATION/CodeQL_alert_page.png) ### Code scanning alerts bulk dismissal tool ##### - currently, GitHub allows for only 25 code scanning alerts to be dismissed at a time. Sometimes, you might have hundreds you would like to dismiss, so you will have to click many times and wait for a long time to dismiss them. Via the "csa-bulk-dismissal.yml", you can automatically dismiss unnecessary alerts or manually do that with one click. NOTE: This tool executes automatically when **Notepads CI/CD Pipeline** action completes. #### 1. Setup 1. In the repository, go to the **Settings** tab -> **Secrets** ![CSA_secrets](ScreenShots/CI-CD_DOCUMENTATION/CSA_secrets.png) 2. Add the following secrets with the name and the corresponding value, by at the upper right of the section, clicking on the **New repository secret** button: ![CSA_new_secret](ScreenShots/CI-CD_DOCUMENTATION/CSA_new_secret.png) ![CSA_secret_add](ScreenShots/CI-CD_DOCUMENTATION/CSA_secret_add.png) - CSA_ACCESS_TOKEN - [create a PAT with "security_events" permission only](#7-how-to-create-a-pat). #### 2. Execution 1. This tool is automatically triggered when **Notepads CI/CD Pipeline** task completes, if you want to manually execute this follow next steps 2. In your repo, click on the Actions tab and on the left, in the Workflows list, click on the "Code scanning alerts bulk dismissal" ![CSA_execute_1](ScreenShots/CI-CD_DOCUMENTATION/CSA_execute_1.png) 3. On the right, click on the "Run workflow" dropdown. Under "Use workflow from" choose your default branch (usually main/master), in the **Type of filter to use** field type "path"/"desc" depending upon whether dismiss alerts based on predefined paths or description respectively (default is "path"), in the **Reason for dismissal** type "fp"/"wf"/"ut" for "false positive"/"won't fix"/"used in tests" respectively (default is "wf") and click on the **Run workflow** button ![CSA_execute_2](ScreenShots/CI-CD_DOCUMENTATION/CSA_execute_2.png) NOTE: if any unsupported values are entered default values will be used 4. If everything was set up currently in the "Setup" phase, the "Code scanning alerts bulk dismissal" workflow is going to be executed successfully, which after some time, would result in **all** previously open code scanning alerts, with a certain description be dismissed ![CSA_execute_3](ScreenShots/CI-CD_DOCUMENTATION/CSA_execute_3.png) ![CSA_execute_4](ScreenShots/CI-CD_DOCUMENTATION/CSA_execute_4.png) ![CSA_execute_5](ScreenShots/CI-CD_DOCUMENTATION/CSA_execute_5.png) NOTE: "closed" refers to "dismissed" alerts #### 3. Customization The "setup" job in the pipeline, allows for more precise filtering of alerts to bulk dismiss. It uses the filter type to choose (filter based on path or description) from the alert to determine if it has to be dismissed or not. We've added the following paths and alert descriptions by default: ##### Paths: - "\*/obj/\*" (if path contains `obj` folder at any position) ##### Descriptions: - "Calls to unmanaged code" - "Unmanaged code" ##### To add more paths, follow these steps: 1. In your source code, open ".github/workflows/csa-bulk-dismissal.yml" 2. From line 50 to 56, notice "$MATRIX = **". This is the [powershell hashtable](https://docs.microsoft.com/powershell/scripting/learn/deep-dives/everything-about-hashtable?view=powershell-7.1) of filters that the CSABD (Code scanning alerts bulk dismissal) tool uses to filter through the alerts: ![CSA_custom_3](ScreenShots/CI-CD_DOCUMENTATION/CSA_custom_3.png) 3. To add more paths under **include** element use comma separation and followed from next line add `@{ filter = "New path" }`. Replace "New path" with the path (with or without [wild cards](https://docs.microsoft.com/powershell/module/microsoft.powershell.core/about/about_wildcards?view=powershell-7.1)) you want: ![CSA_custom_4](ScreenShots/CI-CD_DOCUMENTATION/CSA_custom_4.png) ##### To add more descriptions, follow these steps: 1. In your source code, open ".github/workflows/csa-bulk-dismissal.yml" 2. From line 58 to 67, notice "$MATRIX = **". This is the [powershell hashtable](https://docs.microsoft.com/powershell/scripting/learn/deep-dives/everything-about-hashtable?view=powershell-7.1) of filters that the CSABD (Code scanning alerts bulk dismissal) tool uses to filter through the alerts: ![CSA_custom_1](ScreenShots/CI-CD_DOCUMENTATION/CSA_custom_1.png) 3. To add more descriptions under **include** element use comma separation and followed from next line add `@{ filter = "New description" }`. Replace "New description" with the description you want: ![CSA_custom_2](ScreenShots/CI-CD_DOCUMENTATION/CSA_custom_2.png) ##### To change default filter type and dismissal reason, follow these steps: 1. In your source code, open ".github/workflows/csa-bulk-dismissal.yml" 2. To change default filter type change **$FILTER_TYPE** variable in line 31 to something else (default is "path", supported are: "desc" and "path"): ![CSA_custom_5](ScreenShots/CI-CD_DOCUMENTATION/CSA_custom_5.png) 3. To change dismissal reason change **$REASON** variable in line 45 to something else (default is "won't fix", supported are: "false positive", "won't fix" and "used in tests"): ![CSA_custom_6](ScreenShots/CI-CD_DOCUMENTATION/CSA_custom_6.png) NOTE: changing default filter type and dismissal reason won't change dafault value typed when [manually executing](#csa_execute) tool, change values in line 13 and 17 respectively to reflect the change ![CSA_custom_7](ScreenShots/CI-CD_DOCUMENTATION/CSA_custom_7.png)
## 5. Automated GitHub release When triggered bumps up the GitHub tag in the repo and executes the CD job and produces release with changelogs Note: **not every commit to your master branch are included in changelog** #### Setup Add the following secrets by going to the repo **Settings** tab -> **Secrets**: 1. **PACKAGE_CERTIFICATE_BASE64** - used to dynamically create the PFX file required for the signing of the **msixbundle** - use the following PowerShell code locally to turn your PFX file into Base64: ``` # read from PFX as binary $PFX_FILE = [IO.File]::ReadAllBytes('absolute_path_to_PFX') # convert to Base64 and write in txt [System.Convert]::ToBase64String($PFX_FILE) | Out-File 'absolute_path\cert.txt' ``` - copy the contents of the **cert.txt** and paste as the value of the secret 2. **PACKAGE_CERTIFICATE_PWD** - used in the build of the project to authenticate the PFX - copy and paste the password of your PFX as the value of this secret NOTE: - none of those values are visible in the logs of the pipeline, nor are available to anyone outside of the original repository e.g. forks, anonymous clones etc. - the dynamically created PFX file lives only for the duration of the pipeline execution #### Execution [Once you've set up all the steps for manual execution of the "Notepads CI/CD Pipeline" workflow correctly](#workflow_dispatch), you should be able to successfully trigger release with the same workflow. 1. Go to the project's GitHub repository and click on the **Actions** tab 2. From the "Workflows" list on the left, click on "Notepads CI/CD Pipeline" 3. On the right, next to the "This workflow has a workflow_dispatch event trigger" label, click on the "Run workflow" dropdown, make sure the default branch is selected (if not manually changed, should be main or master) in the "Use workflow from" dropdown, type "release" in the argument textbox (By default "test" is typed) and click the "Run workflow" button ![Actions_workflow_dispatch](ScreenShots/CI-CD_DOCUMENTATION/Actions_workflow_dispatch.png) 4. The workflow will produce release assets and calculate version, generate changelogs from valid commits since previous tag. NOTE: **screenshots are only exemplary**
#### - follow these instructions for any commit (push or PR merge) to your master branch, you would like to see in changelog and count towards version change. You would need one of three keywords at the start of your commit title. Each of the three keywords corresponds to a number in your release version i.e. v1.2.3. The release versioning uses the ["Conventional Commits" specification](https://www.conventionalcommits.org/en/v1.0.0/): - "fix: ..." - this keyword corresponds to the last number v1.2.**3**, also known as PATCH; - "feat: ..." - this keyword corresponds to the middle number v1.**2**.3, also known as MINOR; - "perf: ..." - this keyword corresponds to the first number v**1**.2.3, also known as MAJOR. In addition, to trigger a MAJOR release, you would need to write "BREAKING CHANGE: ..." in the description of the commit, with an empty line above it to indicate it is in the