├── .editorconfig ├── .gitattributes ├── .github ├── CODEOWNERS ├── actions │ └── oidc-auth-flow │ │ └── action.yml ├── dependabot.yml └── workflows │ ├── TestCase.yml │ ├── build-docs-verifier.yml │ ├── codeql-analysis.yml │ ├── dependabot-approve-and-automerge.yml │ ├── dogfood.yml │ ├── dotnet-build-validation.yml │ ├── node-build-validation.yml │ ├── quest-bulk.yml │ └── quest.yml ├── .gitignore ├── .repoman.yml ├── CODE-OF-CONDUCT.md ├── DotNet.DocsTools ├── DotNet.DocsTools.csproj ├── GitHubClientServices │ ├── GitHubAppClient.cs │ ├── GitHubClient.cs │ ├── GitHubClientBase.cs │ ├── GraphQLPacket.cs │ └── IGitHubClient.cs ├── GitHubObjects │ ├── Actor.cs │ ├── BankruptcyIssue.cs │ ├── CloseBankruptyIssueMutation.cs │ ├── DefaultBranch.cs │ ├── FileHistory.cs │ ├── GitHubLabel.cs │ ├── GitHubObjectExtensions.cs │ ├── IGitHubQueryResult.cs │ ├── Issue.cs │ ├── IssueOrPullRequest.cs │ ├── PullRequestFiles.cs │ ├── QuestIssue.cs │ ├── QuestIssueOrPullRequest.cs │ ├── QuestPullRequest.cs │ ├── ResponseExtractors.cs │ ├── SequesteredIssueMutation.cs │ ├── SequesteredIssueOrPullRequestMutation.cs │ ├── SequesteredPullRequestMutation.cs │ ├── StoryPointSize.cs │ └── WhatsNewPullRequest.cs ├── GraphQLQueries │ ├── Common.cs │ ├── EnumerationQuery.cs │ ├── IGitHubMutation.cs │ ├── LabeledIssueCounts.cs │ ├── Mutation.cs │ └── ScalarQuery.cs ├── OspoClientServices │ ├── GitHubInfo.cs │ ├── MicrosoftInfo.cs │ ├── OspoClient.cs │ ├── OspoException.cs │ ├── OspoLink.cs │ ├── OspoLinkSet.cs │ └── OspoUnauthorizedException.cs ├── RESTQueries │ └── PullRequestFilesRequest.cs ├── Serialization │ └── JsonSerializerOptionsDefaults.cs └── Utility │ ├── CommandLineUtility.cs │ ├── ContentScrubber.cs │ ├── DateRange.cs │ ├── EchoLogging.cs │ ├── RawContentFromLocalFile.cs │ └── SprintDateRange.cs ├── DotnetDocsToolsTests ├── DotnetDocsTools.Tests.csproj ├── FakeGitHubClient.cs ├── GraphQLProcessingTests │ ├── ActorNodeTests.cs │ ├── DefaultBranchTests.cs │ ├── FilesInPRTests.cs │ ├── PullRequestPerSprintTests.cs │ ├── QuestIssueTests.cs │ └── ScalarQueryTests.cs ├── RESTProcessingTests │ └── PullRequestFilesQueryTests.cs └── Utility │ ├── ContentScrubberTests.cs │ ├── DateRangeTests.cs │ └── SprintDateRangeTests.cs ├── GitHub.QuerySandbox ├── GitHub.QuerySandbox.csproj ├── GlobalUsings.cs ├── Program.cs ├── Spinners │ └── TimeTravelSpinner.cs └── github-query-sandbox.sln ├── GitHub.RepositoryExplorer.Client ├── App.razor ├── Components │ ├── ConfigureRepo.razor │ ├── ConfigureRepo.razor.cs │ └── ProgressIndicator.razor ├── Extensions │ └── LocalStorageServiceExtensions.cs ├── GitHub.RepositoryExplorer.Client.csproj ├── GlobalUsings.cs ├── HttpClientNames.cs ├── Models │ ├── IssueSummary.cs │ ├── RepoLabels.cs │ └── Repository.cs ├── Options │ └── IssuesApiOptions.cs ├── Pages │ ├── Areas.razor │ ├── Areas.razor.cs │ ├── Areas.razor.css │ ├── ClassificationLineChart.razor │ ├── ClassificationLineChart.razor.cs │ ├── Index.razor │ ├── PriorityLineChart.razor │ ├── PriorityLineChart.razor.cs │ ├── ProductLineChartJS.razor │ ├── ProductLineChartJS.razor.cs │ ├── SummaryChartJS.razor │ └── SummaryChartJS.razor.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Services │ ├── AppInMemoryStateService.cs │ ├── DailyRecordFactory.cs │ ├── IssueSnapshotsClient.cs │ ├── IssuesByPriorityClassification.cs │ ├── IssuesByPriorityClient.cs │ ├── IssuesClient.cs │ └── RespositoryLabelsClient.cs ├── Shared │ ├── MainLayout.razor │ ├── MainLayout.razor.css │ ├── NavMenu.razor │ └── NavMenu.razor.css ├── _Imports.razor └── wwwroot │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── css │ ├── app.css │ ├── bootstrap │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ └── open-iconic │ │ ├── FONT-LICENSE │ │ ├── ICON-LICENSE │ │ ├── README.md │ │ └── font │ │ ├── css │ │ └── open-iconic-bootstrap.min.css │ │ └── fonts │ │ ├── open-iconic.eot │ │ ├── open-iconic.otf │ │ ├── open-iconic.svg │ │ ├── open-iconic.ttf │ │ └── open-iconic.woff │ ├── favicon.ico │ ├── icon-192.png │ └── index.html ├── GitHub.RepositoryExplorer.Functions ├── .gitignore ├── CaptureDailyIssueCountsFunction.cs ├── Configuration │ ├── RepositoriesConfig.cs │ └── RepositoryConfig.cs ├── GitHub.RepositoryExplorer.Functions.csproj ├── Properties │ ├── ServiceDependencies │ │ └── issue-statistics-functions - Zip Deploy │ │ │ └── profile.arm.json │ ├── serviceDependencies.json │ └── serviceDependencies.local.json ├── README.md ├── Startup.cs ├── appsettings.Development.json ├── appsettings.json └── host.json ├── GitHub.RepositoryExplorer.Models ├── DateOnlyConverter.cs ├── Extensions │ ├── DailyRecordExtensions.cs │ └── IssueMatrixExtensions.cs ├── GitHub.RepositoryExplorer.Models.csproj ├── IssueClassificationModel.cs ├── IssuesSnapshot.cs ├── RepositoryLabelConfig.cs ├── SnapshotKey.cs └── dotnet-docs.json ├── GitHub.RepositoryExplorer.Services ├── GitHub.RepositoryExplorer.Services.csproj ├── IssueCountGenerator.cs └── IssueCountStorage.cs ├── GitHub.RepositoryExplorer.WebApi ├── Controllers │ ├── IssueSnapshotsController.cs │ ├── IssuesController.cs │ └── RepositoryLabelsController.cs ├── CorsPolicy.cs ├── GitHub.RepositoryExplorer.WebApi.csproj ├── GlobalUsings.cs ├── Program.cs ├── Properties │ ├── launchSettings.json │ ├── serviceDependencies.json │ └── serviceDependencies.local.json ├── Services │ └── IssueCountService.cs ├── appsettings.Development.json └── appsettings.json ├── GitHub.RepositoryExplorer └── GitHub.RepositoryExplorer.sln ├── IssueCloser ├── BulkCloseConfig.cs ├── CloseCriteria.cs ├── IssueCloser.csproj ├── IssueCloser │ └── IssueCloser.sln ├── IssueSet.cs ├── Priorities.cs ├── Program.cs └── bulkcloseconfig.json ├── LICENSE ├── LICENSE-CODE ├── PackageIndexer ├── CsvEntry.cs ├── CsvUtils.cs ├── DotnetPackageIndex.cs ├── FindProjectsWithDocs.ps1 ├── NuGet │ ├── NuGetFeed.cs │ ├── NuGetFeeds.cs │ └── NuGetStore.cs ├── PackageEntry.cs ├── PackageExtensions.cs ├── PackageFilter.cs ├── PackageIndexer.cs ├── PackageIndexer.csproj ├── PlatformPackageDefinition.cs ├── Program.cs └── XmlEntryFormat.cs ├── README.md ├── RepoMan ├── .gitignore ├── .repoman.yml ├── Actions │ ├── Assignees.cs │ ├── CloseObject.cs │ ├── Comment.cs │ ├── File.cs │ ├── Labels.cs │ ├── Milestone.cs │ ├── ProductTechLabels.cs │ ├── Project.cs │ ├── Reviewers.cs │ └── Variables.cs ├── Checks │ ├── CommentBody.cs │ ├── DocMetadata.cs │ ├── DocMetadataExists.cs │ ├── DocNewMetadataExists.cs │ ├── ForceFail.cs │ ├── Group.cs │ ├── ICheck.cs │ ├── IsDraft.cs │ ├── Query.cs │ └── Variable.cs ├── Function1.cs ├── GithubCommand.cs ├── ILoggerExtensions.cs ├── IRunnerItem.cs ├── Program.cs ├── Properties │ ├── ServiceDependencies │ │ ├── repoman - Web Deploy │ │ │ └── profile.arm.json │ │ └── repoman - Zip Deploy │ │ │ ├── appInsights1.arm.json │ │ │ └── profile.arm.json │ ├── serviceDependencies.json │ ├── serviceDependencies.local.json │ └── serviceDependencies.repoman - Zip Deploy.json ├── RepoMan.csproj ├── RepoMan.sln ├── RequestType.cs ├── Runner.cs ├── State.cs ├── Types.cs ├── Utilities.cs ├── YamlExtensions.cs ├── host.json ├── readme.md └── state.json ├── RepoManChecker ├── CommandCheck.cs ├── CommandRun.cs ├── Program.cs ├── RepoManCheckerCLI.csproj └── state-issues-opened.json ├── Sandbox ├── Program.cs └── Sandbox.csproj ├── SmallRepo ├── Program.cs ├── SmallRepo.csproj └── action.yml ├── ThirdPartyNotices.md ├── Whats-new └── Whats-new.sln ├── WhatsNew.Cli ├── .vscode │ └── extensions.json ├── CONTRIBUTING.md ├── Program.cs ├── README.md ├── WhatsNew.Cli.csproj ├── action.yml └── nuget │ └── images │ └── docs-logo-ms.png ├── WhatsNew.Infrastructure.Tests ├── Models │ └── PageGeneratorInputTests.cs ├── Services │ ├── ConfigurationServiceTests.cs │ └── SchemaValidationServiceTests.cs ├── WhatsNew.Infrastructure.Tests.csproj ├── assets │ ├── MicrosoftDocs │ │ ├── azure-devops-docs-pr.json │ │ └── cpp-docs-pr.json │ └── dotnet │ │ ├── AspNetCore.Docs.json │ │ └── docs.json └── xunit.runner.json ├── WhatsNew.Infrastructure ├── Configuration │ └── reposettings.schema.json ├── Constants.cs ├── Models │ ├── DocLinkSettings.cs │ ├── InclusionCriteria.cs │ ├── Landing.cs │ ├── NavigationDetails.cs │ ├── PageGeneratorInput.cs │ ├── RepositoryArea.cs │ ├── RepositoryDetail.cs │ ├── Toc.cs │ └── WhatsNewConfiguration.cs ├── Services │ ├── ConfigurationService.cs │ ├── IndexUpdateService.cs │ ├── PageGenerationService.cs │ ├── SchemaValidationService.cs │ └── TocUpdateService.cs └── WhatsNew.Infrastructure.csproj ├── XmlDocConflictResolver ├── ConflictChecker.cs ├── Docs │ ├── APIKind.cs │ ├── DocsAPI.cs │ ├── DocsAssemblyInfo.cs │ ├── DocsCommentsContainer.cs │ ├── DocsException.cs │ ├── DocsMember.cs │ ├── DocsMemberSignature.cs │ ├── DocsParam.cs │ ├── DocsRelated.cs │ ├── DocsType.cs │ ├── DocsTypeParam.cs │ ├── DocsTypeSignature.cs │ └── IDocsAPI.cs ├── IntelliSenseXml │ ├── IntelliSenseXmlCommentsContainer.cs │ ├── IntelliSenseXmlException.cs │ ├── IntelliSenseXmlFile.cs │ ├── IntelliSenseXmlMember.cs │ ├── IntelliSenseXmlParam.cs │ └── IntelliSenseXmlTypeParam.cs ├── Log.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── XmlDocConflictResolver.csproj └── XmlHelper.cs ├── actions ├── dependabot-bot │ ├── .dockerignore │ ├── .gitignore │ ├── README.md │ ├── action.yml │ ├── dependabot-bot.sln │ ├── packages-ignore.json │ └── src │ │ └── dependabot-bot │ │ ├── Dockerfile │ │ ├── Extensions │ │ └── StringBuilderExtensions.cs │ │ ├── GlobalUsings.cs │ │ ├── Program.Regex.cs │ │ ├── Program.Services.cs │ │ ├── Program.cs │ │ └── dependabot-bot.csproj ├── docs-verifier │ ├── .editorconfig │ ├── .gitignore │ ├── Directory.Build.props │ ├── Dockerfile │ ├── MSDocsBuildVerifier.sln │ ├── README.md │ ├── action.yml │ ├── docs │ │ └── json-config-file.md │ ├── eng │ │ └── Settings.props │ ├── nuget.config │ ├── src │ │ ├── ActionRunner │ │ │ ├── ActionRunner.csproj │ │ │ └── Program.cs │ │ ├── BuildVerifier.IO.Abstractions │ │ │ ├── BaseConfigurationReader.cs │ │ │ ├── BaseMappedConfigurationReader.cs │ │ │ └── BuildVerifier.IO.Abstractions.csproj │ │ ├── GitHub │ │ │ ├── GitHub.csproj │ │ │ ├── GitHubPullRequest.cs │ │ │ └── PullRequestFileExtensions.cs │ │ ├── MarkdownLinksVerifier │ │ │ ├── Configuration │ │ │ │ ├── ConfigurationReader.cs │ │ │ │ └── MarkdownLinksVerifierConfiguration.cs │ │ │ ├── LinkClassifier │ │ │ │ ├── Classifier.cs │ │ │ │ └── LinkClassification.cs │ │ │ ├── LinkValidator │ │ │ │ ├── ILinkValidator.cs │ │ │ │ ├── LinkValidatorCreator.cs │ │ │ │ ├── LocalLinkValidator.cs │ │ │ │ ├── MailtoLinkValidator.cs │ │ │ │ ├── OnlineLinkValidator.cs │ │ │ │ └── ValidationResult.cs │ │ │ ├── MarkdownFilesAnalyzer.cs │ │ │ └── MarkdownLinksVerifier.csproj │ │ └── RedirectionVerifier │ │ │ ├── DocfxConfiguration.cs │ │ │ ├── DocfxConfigurationReader.cs │ │ │ ├── NavigationOptions.cs │ │ │ ├── OpenPublishingConfig.cs │ │ │ ├── OpenPublishingConfigReader.cs │ │ │ ├── OpenPublishingRedirectionReader.cs │ │ │ ├── OpenPublishingRedirections.cs │ │ │ ├── Redirection.cs │ │ │ ├── RedirectionHelpers.cs │ │ │ ├── RedirectionVerifier.csproj │ │ │ ├── RedirectionsVerifier.cs │ │ │ ├── WhatsNewConfiguration.cs │ │ │ └── WhatsNewConfigurationReader.cs │ ├── tests │ │ ├── GitHub.UnitTests │ │ │ ├── GitHub.UnitTests.csproj │ │ │ └── PullRequestFileExtensionsTests.cs │ │ └── MarkdownLinksVerifier │ │ │ ├── ConfigurationTests │ │ │ └── ConfigurationReaderTests.cs │ │ │ ├── GlobalSuppressions.cs │ │ │ ├── LinkClassifierTests.cs │ │ │ ├── LinkValidatorTests │ │ │ ├── LocalLinkValidatorTests.cs │ │ │ ├── MailtoLinkValidatorTests.cs │ │ │ └── Utilities │ │ │ │ ├── FilesCollection.cs │ │ │ │ └── Workspace.cs │ │ │ └── MarkdownLinksVerifier.UnitTests.csproj │ └── valid-test-cases │ │ ├── MSDocsSpecific │ │ ├── Includes │ │ │ ├── aspnetcore.md │ │ │ └── include.md │ │ └── Includes2 │ │ │ ├── core │ │ │ ├── compatibility │ │ │ │ └── 2.1.md │ │ │ └── tools │ │ │ │ └── sdk-errors │ │ │ │ └── netsdk1059.md │ │ │ └── includes │ │ │ └── dotnetclitoolreference.md │ │ ├── MarkdownLinksVerifier │ │ ├── test-query-parameters │ │ │ ├── File.md │ │ │ └── image.png │ │ └── test1 │ │ │ ├── File1.md │ │ │ └── folder │ │ │ └── Name With Space.md │ │ └── README.md ├── dotnet-version-updater │ ├── action.yml │ └── upgrade-projects.ps1 ├── sequester │ ├── .dockerignore │ ├── .gitattributes │ ├── .gitignore │ ├── ImportIssues │ │ ├── GlobalUsings.cs │ │ ├── ImportIssues.csproj │ │ └── Program.cs │ ├── Quest2GitHub.Tests │ │ ├── BuildExtendedPropertiesTests.cs │ │ ├── GetIterationTests.cs │ │ ├── GlobalUsings.cs │ │ ├── ImportOptionsTests.cs │ │ ├── Quest2GitHub.Tests.csproj │ │ ├── QuestWorkItemTests.cs │ │ ├── RawGitHubFileReaderTests.cs │ │ └── quest-import.json │ ├── Quest2GitHub.sln │ ├── Quest2GitHub │ │ ├── AzDoClientServices │ │ │ ├── JsonPatchDocument.cs │ │ │ └── QuestClient.cs │ │ ├── Extensions │ │ │ ├── ImportOptionsExtensions.cs │ │ │ └── ServiceCollectionExtensions.cs │ │ ├── GlobalUsings.cs │ │ ├── Models │ │ │ ├── IssueExtensions.cs │ │ │ ├── QuestIteration.cs │ │ │ ├── QuestWorkItem.cs │ │ │ └── WorkItemProperties.cs │ │ ├── Options │ │ │ ├── ApiKeys.cs │ │ │ ├── AzureDevOpsOptions.cs │ │ │ ├── EnvironmentVariableReader.cs │ │ │ ├── ImportOptions.cs │ │ │ ├── LocalFileReader.cs │ │ │ └── RawGitHubFileReader.cs │ │ ├── Quest2GitHub.csproj │ │ └── QuestGitHubService.cs │ ├── README.md │ └── action.yml └── status-checker │ ├── .eslintignore │ ├── .eslintrc.json │ ├── .gitattributes │ ├── .gitignore │ ├── .prettierignore │ ├── README.md │ ├── __tests__ │ ├── 3 │ │ └── three.md │ ├── file-heading-extractor.test.ts │ ├── main.test.ts │ ├── no-heading.md │ ├── pull-updater.test.ts │ └── sample.md │ ├── action.yml │ ├── dist │ ├── index.js │ ├── index.js.map │ ├── licenses.txt │ └── sourcemap-register.js │ ├── jest.config.js │ ├── package-lock.json │ ├── package.json │ ├── src │ ├── file-heading-extractor.ts │ ├── main.ts │ ├── pull-updater.ts │ ├── status-checker.ts │ ├── types │ │ ├── ChangeType.ts │ │ ├── FileChange.ts │ │ ├── Mode.ts │ │ ├── NodeOf.ts │ │ ├── PageInfo.ts │ │ ├── Pull.ts │ │ ├── PullRequestDetails.ts │ │ ├── PullRequestState.ts │ │ └── WorkflowInput.ts │ └── wait.ts │ └── tsconfig.json ├── cleanrepo.Dockerfile ├── cleanrepo ├── CleanRepo.csproj ├── Extensions │ └── TimeSpanExtensions.cs ├── GlobalSuppressions.cs ├── Options.cs ├── Program.cs ├── README.md ├── Redirect.cs ├── RedirectionFile.cs ├── Repo.cs ├── action.yml ├── appSettings.json └── multiplexer.sh ├── docs-tools.sln ├── quest-config.json ├── sequester.Dockerfile ├── smalltest.Dockerfile ├── snippets5000 ├── Get-MSBuildResults.ps1 ├── Out-GithubActionStatus.ps1 ├── PullRequestSimulations.Generators │ ├── PullRequestSimulations.Generators.csproj │ └── TestGenerator.cs ├── PullRequestSimulations │ ├── LocalTests.cs │ ├── PullRequestSimulations.csproj │ ├── Usings.cs │ ├── data.json │ └── snippets │ │ ├── bad │ │ ├── lots-o-projects │ │ │ ├── extensions │ │ │ │ ├── LinqExtensions.cs │ │ │ │ ├── Program.cs │ │ │ │ └── linq.csproj │ │ │ ├── linq-snippets.sln │ │ │ └── partition_not_in_sln │ │ │ │ ├── Program.cs │ │ │ │ └── partition.csproj │ │ ├── nullablepatternmatching │ │ │ └── Program.cs │ │ ├── patternmatching │ │ │ ├── Program.cs │ │ │ ├── childfolder │ │ │ │ ├── Program.cs │ │ │ │ └── other.csproj │ │ │ └── patternmatching.csproj │ │ ├── samefolder │ │ │ ├── Program.cs │ │ │ ├── project1.csproj │ │ │ └── project2.vbproj │ │ └── sln_no_proj │ │ │ ├── file.sln │ │ │ └── some_code │ │ │ ├── Planet.cs │ │ │ ├── PlanetType.cs │ │ │ ├── Program.DistinctBy.cs │ │ │ ├── Program.ExceptBy.cs │ │ │ ├── Program.IntersectBy.cs │ │ │ ├── Program.UnionBy.cs │ │ │ └── Program.cs │ │ └── good │ │ ├── deeper-path │ │ ├── finished │ │ │ └── toll-calculator │ │ │ │ ├── ExternalSystems.cs │ │ │ │ ├── Program.cs │ │ │ │ ├── TollCalculator.cs │ │ │ │ └── toll-calculator.csproj │ │ ├── start │ │ │ └── toll-calculator │ │ │ │ ├── ExternalSystems.cs │ │ │ │ ├── Program.cs │ │ │ │ └── toll-calculator.csproj │ │ └── three_projs │ │ │ ├── cpp │ │ │ ├── MyForm.cpp │ │ │ ├── MyForm.h │ │ │ ├── MyForm.resx │ │ │ ├── Student.h │ │ │ ├── Subject.h │ │ │ ├── TextBook.h │ │ │ ├── project.vcxproj │ │ │ ├── project.vcxproj.filters │ │ │ └── snippets.5000.json │ │ │ ├── cs │ │ │ ├── Form1.Designer.cs │ │ │ ├── Form1.cs │ │ │ ├── Form1.resx │ │ │ ├── Program.cs │ │ │ ├── Student.cs │ │ │ ├── Subject.cs │ │ │ ├── TextBook.cs │ │ │ ├── project.csproj │ │ │ └── snippets.5000.json │ │ │ └── vb │ │ │ ├── App.config │ │ │ ├── Form1.Designer.vb │ │ │ ├── Form1.resx │ │ │ ├── Form1.vb │ │ │ ├── My Project │ │ │ ├── Application.Designer.vb │ │ │ ├── Application.myapp │ │ │ ├── AssemblyInfo.vb │ │ │ ├── Resources.Designer.vb │ │ │ ├── Resources.resx │ │ │ ├── Settings.Designer.vb │ │ │ └── Settings.settings │ │ │ ├── Student.vb │ │ │ ├── Subject.vb │ │ │ ├── TextBook.vb │ │ │ └── project.vbproj │ │ ├── normal │ │ ├── asandis │ │ │ ├── Program.cs │ │ │ └── asandis.csproj │ │ ├── csharp_project │ │ │ ├── Program.cs │ │ │ ├── app1.csproj │ │ │ └── snippets.5000.json │ │ ├── deleted_code │ │ │ ├── snippets.5000.json │ │ │ └── some-other-artifact.txt │ │ ├── nullablepatternmatching │ │ │ ├── Program.cs │ │ │ └── nullablepatternmatching.csproj │ │ ├── patternmatching │ │ │ ├── Program.cs │ │ │ └── patternmatching.csproj │ │ └── vb_project │ │ │ ├── Program.vb │ │ │ └── app1.vbproj │ │ └── solutions │ │ ├── lots-o-projects │ │ ├── extensions │ │ │ ├── LinqExtensions.cs │ │ │ ├── Program.cs │ │ │ └── linq.csproj │ │ ├── linq-snippets.sln │ │ ├── partition │ │ │ ├── Program.cs │ │ │ └── partition.csproj │ │ ├── projection │ │ │ ├── Program.ZipResult.cs │ │ │ ├── Program.ZipTriple.cs │ │ │ ├── Program.ZipTuple.cs │ │ │ ├── Program.cs │ │ │ └── projection.csproj │ │ └── set-operators │ │ │ ├── Planet.cs │ │ │ ├── PlanetType.cs │ │ │ ├── Program.DistinctBy.cs │ │ │ ├── Program.ExceptBy.cs │ │ │ ├── Program.IntersectBy.cs │ │ │ ├── Program.UnionBy.cs │ │ │ ├── Program.cs │ │ │ └── set-operators.csproj │ │ ├── single-project │ │ ├── linq-snippets.sln │ │ └── set-operators │ │ │ ├── Planet.cs │ │ │ ├── PlanetType.cs │ │ │ ├── Program.DistinctBy.cs │ │ │ ├── Program.ExceptBy.cs │ │ │ ├── Program.IntersectBy.cs │ │ │ ├── Program.UnionBy.cs │ │ │ ├── Program.cs │ │ │ └── set-operators.csproj │ │ └── sln_odd_proj │ │ ├── file.sln │ │ └── some_code │ │ ├── Planet.cs │ │ ├── PlanetType.cs │ │ ├── Program.DistinctBy.cs │ │ ├── Program.ExceptBy.cs │ │ ├── Program.IntersectBy.cs │ │ ├── Program.UnionBy.cs │ │ ├── Program.cs │ │ └── project1.proj └── Snippets5000 │ ├── DiscoveryResult.cs │ ├── Extensions.cs │ ├── FullBuildProjectList.cs │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── PullRequestProcessor.cs │ ├── PullRequestSimulationsHelpers │ ├── ChangeItem.cs │ ├── ChangeItemType.cs │ ├── ExpectedResult.cs │ └── PullRequest.cs │ ├── Snippets5000.csproj │ ├── Snippets5000.sln │ ├── SnippetsConfigFile.cs │ └── TestingProjectList.cs └── whatsnew.Dockerfile /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files you want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.c text 7 | *.h text 8 | 9 | # Declare files that will always have CRLF line endings on checkout. 10 | *.sln text eol=crlf 11 | 12 | # Denote all files that are truly binary and should not be modified. 13 | *.png binary 14 | *.jpg binary -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | 2 | * @dotnet/docs 3 | 4 | actions/dependabot-bot/ @IEvangelist 5 | actions/docs-verifier/ @BillWagner @IEvangelist 6 | actions/dotnet-version-updater/ @IEvangelist 7 | actions/sequester/ @BillWagner 8 | actions/status-checker/ @gewarren 9 | cleanrepo/ @gewarren 10 | DotNet.DocsTools/ @IEvangelist @BillWagner 11 | DotNet.DocsToolsTests/ @IEvangelist @BillWagner 12 | GitHub.QuerySandbox/ @BillWagner 13 | GitHub.RepositoryExplorer/ @BillWagner 14 | GitHub.RepositoryExplorer.Client/ @BillWagner 15 | GitHub.RepositoryExplorer.Functions/ @BillWagner 16 | GitHub.RepositoryExplorer.Models/ @BillWagner 17 | GitHub.RepositoryExplorer.Services/ @BillWagner 18 | GitHub.RepositoryExplorer.WebApi/ @BillWagner 19 | IssueCloser/ @BillWagner 20 | PackageIndexer/ @gewarren 21 | RepoMan/ @adegeo 22 | RepoManChecker/ @adegeo 23 | snippets5000/ @adegeo @BillWagner 24 | Whats-new/ @BillWagner 25 | WhatsNew.Cli/ @BillWagner 26 | WhatsNew.Infrastructure/ @BillWagner 27 | WhatsNew.Infrastructure.Tests/ @BillWagner 28 | XmlDocConflictResolver/ @gewarren 29 | 30 | -------------------------------------------------------------------------------- /.github/actions/oidc-auth-flow/action.yml: -------------------------------------------------------------------------------- 1 | name: Azure OIDC auth flow 2 | description: "Azure OpenID Connect authentication flow" 3 | 4 | inputs: 5 | client-id: 6 | description: "The Azure AD application client ID" 7 | required: true 8 | tenant-id: 9 | description: "The Azure AD tenant ID" 10 | required: true 11 | audience: 12 | description: "The audience for the access token" 13 | required: true 14 | 15 | outputs: 16 | access-token: 17 | description: "The Azure OIDC bearer access token" 18 | value: ${{ steps.api-access.outputs.AZURE_ACCESS_TOKEN }} 19 | 20 | runs: 21 | using: "composite" 22 | steps: 23 | - name: Azure OpenID Connect 24 | uses: azure/login@v2 25 | with: 26 | client-id: ${{ inputs.client-id }} 27 | tenant-id: ${{ inputs.tenant-id }} 28 | audience: ${{ inputs.audience }} 29 | allow-no-subscriptions: true 30 | 31 | - name: OSMP API access 32 | id: api-access 33 | shell: bash 34 | run: | 35 | TOKEN=$(az account get-access-token --query 'accessToken' -o tsv --resource ${{ inputs.audience }}) 36 | echo "AZURE_ACCESS_TOKEN=$(echo $TOKEN)" >> $GITHUB_OUTPUT 37 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | day: "wednesday" 9 | open-pull-requests-limit: 10 10 | # NuGet packages 11 | - package-ecosystem: "nuget" 12 | directory: "/" 13 | schedule: 14 | interval: "weekly" 15 | day: "wednesday" 16 | open-pull-requests-limit: 5 17 | groups: 18 | dotnet: 19 | patterns: 20 | - "*" 21 | # NPM packages 22 | - package-ecosystem: "npm" 23 | directory: "/" 24 | schedule: 25 | interval: "weekly" 26 | day: "wednesday" 27 | open-pull-requests-limit: 5 28 | groups: 29 | npm: 30 | patterns: 31 | - "*" 32 | # Dockerfiles 33 | - package-ecosystem: "docker" 34 | directory: "/" 35 | schedule: 36 | interval: "weekly" 37 | day: "wednesday" 38 | open-pull-requests-limit: 5 39 | groups: 40 | docker: 41 | patterns: 42 | - "*" 43 | -------------------------------------------------------------------------------- /.github/workflows/dependabot-approve-and-automerge.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-approve and auto-merge 2 | on: pull_request 3 | 4 | permissions: 5 | contents: write 6 | pull-requests: write 7 | 8 | jobs: 9 | dependabot: 10 | runs-on: ubuntu-latest 11 | if: ${{ github.actor == 'dependabot[bot]' && github.repository_owner == 'dotnet' }} 12 | steps: 13 | - name: Dependabot metadata 14 | id: metadata 15 | uses: dependabot/fetch-metadata@v2 16 | with: 17 | github-token: "${{ secrets.GITHUB_TOKEN }}" 18 | - name: Approve a PR 19 | run: gh pr review --approve "$PR_URL" 20 | env: 21 | PR_URL: ${{github.event.pull_request.html_url}} 22 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 23 | - name: Enable auto-merge for Dependabot PRs 24 | run: gh pr merge --auto --merge "$PR_URL" 25 | env: 26 | PR_URL: ${{github.event.pull_request.html_url}} 27 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 28 | -------------------------------------------------------------------------------- /.github/workflows/dogfood.yml: -------------------------------------------------------------------------------- 1 | name: Dogfood docs-verifier 2 | on: pull_request 3 | 4 | jobs: 5 | validate_links: 6 | name: MSDocs verifier 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout the repository 11 | uses: actions/checkout@main 12 | 13 | - name: Docs verifier 14 | env: 15 | GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }} 16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 17 | uses: ./actions/docs-verifier 18 | -------------------------------------------------------------------------------- /.github/workflows/node-build-validation.yml: -------------------------------------------------------------------------------- 1 | name: node build and test 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'actions/status-checker/**' # Only run for TypeScript action updates 8 | pull_request: 9 | branches: [ main ] 10 | paths: 11 | - 'actions/status-checker/**' # Only run for TypeScript action updates 12 | 13 | jobs: 14 | build: 15 | name: build 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@main 19 | - name: Use Node.js 18 20 | uses: actions/setup-node@main 21 | with: 22 | node-version: 18 23 | cache: 'npm' 24 | cache-dependency-path: ./actions/status-checker/package-lock.json 25 | - run: | 26 | cd ./actions/status-checker/ 27 | npm ci 28 | npm run build --if-present 29 | npm test 30 | -------------------------------------------------------------------------------- /.repoman.yml: -------------------------------------------------------------------------------- 1 | revision: 1 2 | schema-version: 5 3 | owner-ms-alias: adegeo 4 | 5 | config: 6 | DocMetadata: 7 | Headers: 8 | - ["---", "#### "] 9 | 10 | ParserRegex: "^\\* (.*): (.*)$" 11 | 12 | ContentUrlRegex: 13 | - "### Page URL\n\n(.*)" 14 | 15 | issues: 16 | 17 | labeled: 18 | 19 | # Temporary label to mark issues as updated for Quest. The label is instantly removed 20 | - check: 21 | - type: query 22 | value: "length(Issue.Labels[?Name == ':world_map: mapQUEST']) != `0`" 23 | pass: 24 | - labels-remove: [":world_map: mapQUEST"] 25 | 26 | projects_v2_item: 27 | 28 | reordered: 29 | 30 | - labels-add: [":world_map: mapQUEST"] 31 | 32 | edited: 33 | 34 | - check: 35 | - type: query 36 | value: "EventPayload.changes.field_value.field_name == 'Priority' || EventPayload.changes.field_value.field_name == 'Size'" 37 | pass: 38 | - labels-add: [":world_map: mapQUEST"] 39 | -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of conduct 2 | 3 | This project has adopted the code of conduct defined by the Contributor Covenant to clarify expected behavior in our community. 4 | 5 | For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct). 6 | 7 | -------------------------------------------------------------------------------- /DotNet.DocsTools/DotNet.DocsTools.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 2.2.0.0 8 | 2.2.0.0 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /DotNet.DocsTools/GitHubClientServices/GitHubClient.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http.Headers; 2 | 3 | namespace DotNetDocs.Tools.GitHubCommunications; 4 | public sealed class GitHubClient : GitHubClientBase, IGitHubClient, IDisposable 5 | { 6 | internal GitHubClient(string token) 7 | { 8 | Console.WriteLine("Using default GitHub PAT token."); 9 | SetAuthorizationHeader(new AuthenticationHeaderValue("Token", token)); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /DotNet.DocsTools/GitHubClientServices/GraphQLPacket.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | 3 | namespace DotNetDocs.Tools.GitHubCommunications; 4 | 5 | /// 6 | /// This basic class represents a GraphQL post packet. 7 | /// 8 | /// 9 | /// This class represents a query packet. It has the shape expected 10 | /// for a GraphQL query. 11 | /// 12 | public class GraphQLPacket 13 | { 14 | /// 15 | /// The query or mutation string. 16 | /// 17 | public string query { get; set; } = ""; 18 | 19 | /// 20 | /// The dictionary of variables for the query. 21 | /// 22 | public IDictionary variables { get; } = new Dictionary(); 23 | 24 | /// 25 | /// Convert this object to JSON. 26 | /// 27 | /// The minified JSON for this object. 28 | public string ToJsonText() => JsonSerializer.Serialize(this); 29 | } 30 | -------------------------------------------------------------------------------- /DotNet.DocsTools/GitHubObjects/Issue.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | 3 | namespace DotNet.DocsTools.GitHubObjects; 4 | 5 | public abstract record Issue : IssueOrPullRequest 6 | { 7 | public Issue(JsonElement element) : base(element) 8 | { 9 | Body = ResponseExtractors.GetBodyValue(element); 10 | } 11 | 12 | /// 13 | /// The body of the issue 14 | /// 15 | /// 16 | /// This is the body of the issue as markdown text. 17 | /// 18 | public string? Body { get; } 19 | } 20 | -------------------------------------------------------------------------------- /DotNet.DocsTools/GitHubObjects/SequesteredIssueMutation.cs: -------------------------------------------------------------------------------- 1 | using DotNet.DocsTools.GraphQLQueries; 2 | using DotNetDocs.Tools.GitHubCommunications; 3 | 4 | namespace DotNet.DocsTools.GitHubObjects; 5 | 6 | /// 7 | /// The mutation to sequester an issue. 8 | /// 9 | /// 10 | /// This performs three distinct actions in order. First, the "request" label is removed. Second, 11 | /// the body text is updated to add a link to the AzDo work item. Third, the "sequestered label 12 | /// is added. 13 | /// 14 | public class SequesteredIssueMutation : SequesteredIssueOrPullRequestMutation, IGitHubMutation 15 | { 16 | /// 17 | /// Construct the mutation packet 18 | /// 19 | /// The set of variables to use. 20 | /// The packet, including all variables. 21 | public static GraphQLPacket GetMutationPacket(SequesterVariables variables) => 22 | GetMutationPacket(variables, true); 23 | } 24 | -------------------------------------------------------------------------------- /DotNet.DocsTools/GitHubObjects/SequesteredPullRequestMutation.cs: -------------------------------------------------------------------------------- 1 | using DotNet.DocsTools.GraphQLQueries; 2 | using DotNetDocs.Tools.GitHubCommunications; 3 | 4 | namespace DotNet.DocsTools.GitHubObjects; 5 | public class SequesteredPullRequestMutation : SequesteredIssueOrPullRequestMutation, IGitHubMutation 6 | { 7 | /// 8 | /// Construct the mutation packet 9 | /// 10 | /// The set of variables to use. 11 | /// The packet, including all variables. 12 | public static GraphQLPacket GetMutationPacket(SequesterVariables variables) => 13 | GetMutationPacket(variables, false); 14 | } 15 | -------------------------------------------------------------------------------- /DotNet.DocsTools/GraphQLQueries/Common.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | 3 | namespace DotNetDocs.Tools.GraphQLQueries; 4 | 5 | public static class Common 6 | { 7 | public static JsonElement Descendent(this JsonElement element, IEnumerable path) 8 | { 9 | foreach (var item in path) 10 | { 11 | if ((element.ValueKind == JsonValueKind.Null) || (!element.TryGetProperty(item, out element))) 12 | return default; 13 | } 14 | return element; 15 | } 16 | 17 | public static JsonElement Descendent(this JsonElement element, params string[] path) 18 | { 19 | foreach (var item in path) 20 | { 21 | if ((element.ValueKind == JsonValueKind.Null) || (!element.TryGetProperty(item, out element))) 22 | return default; 23 | } 24 | return element; 25 | } 26 | 27 | public static (bool hasNext, string endCursor) NextPageInfo(this JsonElement pageInfoNode) => 28 | (pageInfoNode.Descendent("pageInfo", "hasNextPage").GetBoolean(), 29 | pageInfoNode.Descendent("pageInfo", "endCursor").GetString() ?? string.Empty); 30 | } 31 | -------------------------------------------------------------------------------- /DotNet.DocsTools/GraphQLQueries/IGitHubMutation.cs: -------------------------------------------------------------------------------- 1 | using DotNetDocs.Tools.GitHubCommunications; 2 | 3 | namespace DotNet.DocsTools.GraphQLQueries; 4 | 5 | 6 | /// 7 | /// Interface that collaborates with the class to 8 | /// perform a GitHub mutation. 9 | /// 10 | /// The class that performs a specific mutation. 11 | /// A record that contains the types for the variables in the GraphQL packet. 12 | public interface IGitHubMutation where TMutation : IGitHubMutation 13 | { 14 | /// 15 | /// Return the GraphQL packet for the mutation. 16 | /// 17 | /// A record that defines the variables. 18 | /// The query packet. 19 | public abstract static GraphQLPacket GetMutationPacket(TVariables variables); 20 | } 21 | -------------------------------------------------------------------------------- /DotNet.DocsTools/OspoClientServices/GitHubInfo.cs: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/dotnet/org-policy/tree/main/src/Microsoft.DotnetOrg.Ospo 2 | 3 | namespace Microsoft.DotnetOrg.Ospo; 4 | 5 | #pragma warning disable CS8618 // This is a serialized type. 6 | public sealed class GitHubInfo 7 | { 8 | public int Id { get; set; } 9 | public string Login { get; set; } 10 | public List Organizations { get; set; } 11 | } 12 | #pragma warning restore CS8618 13 | 14 | -------------------------------------------------------------------------------- /DotNet.DocsTools/OspoClientServices/MicrosoftInfo.cs: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/dotnet/org-policy/tree/main/src/Microsoft.DotnetOrg.Ospo 2 | 3 | namespace Microsoft.DotnetOrg.Ospo; 4 | 5 | #pragma warning disable CS8618 // This is a serialized type. 6 | public sealed class MicrosoftInfo 7 | { 8 | public string Alias { get; set; } 9 | public string PreferredName { get; set; } 10 | public string UserPrincipalName { get; set; } 11 | public string EmailAddress { get; set; } 12 | public string Id { get; set; } 13 | } 14 | #pragma warning restore CS8618 15 | 16 | -------------------------------------------------------------------------------- /DotNet.DocsTools/OspoClientServices/OspoException.cs: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/dotnet/org-policy/tree/main/src/Microsoft.DotnetOrg.Ospo 2 | 3 | using System.Net; 4 | 5 | namespace Microsoft.DotnetOrg.Ospo; 6 | 7 | [Serializable] 8 | public class OspoException : Exception 9 | { 10 | public OspoException() 11 | { 12 | } 13 | 14 | public OspoException(string? message) 15 | : base(message) 16 | { 17 | } 18 | 19 | public OspoException(string? message, Exception? inner) 20 | : base(message, inner) 21 | { 22 | } 23 | 24 | public OspoException(string? message, HttpStatusCode code) 25 | : this(message) 26 | { 27 | Code = code; 28 | } 29 | 30 | public HttpStatusCode Code { get; } 31 | } -------------------------------------------------------------------------------- /DotNet.DocsTools/OspoClientServices/OspoLink.cs: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/dotnet/org-policy/tree/main/src/Microsoft.DotnetOrg.Ospo 2 | 3 | using System.Text.Json.Serialization; 4 | 5 | namespace Microsoft.DotnetOrg.Ospo; 6 | 7 | #pragma warning disable CS8618 // This is a serialized type. 8 | public sealed class OspoLink 9 | { 10 | [JsonPropertyName("github")] 11 | public GitHubInfo GitHubInfo { get; set; } 12 | 13 | [JsonPropertyName("aad")] 14 | public MicrosoftInfo MicrosoftInfo { get; set; } 15 | } 16 | #pragma warning restore CS8618 17 | -------------------------------------------------------------------------------- /DotNet.DocsTools/OspoClientServices/OspoLinkSet.cs: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/dotnet/org-policy/tree/main/src/Microsoft.DotnetOrg.Ospo 2 | 3 | using System.Text.Json.Serialization; 4 | 5 | namespace Microsoft.DotnetOrg.Ospo; 6 | 7 | #pragma warning disable CS8618 // This is a serialized type. 8 | public sealed class OspoLinkSet 9 | { 10 | public OspoLinkSet() 11 | { 12 | } 13 | 14 | public void Initialize() 15 | { 16 | LinkByLogin = Links.ToDictionary(l => l.GitHubInfo.Login); 17 | } 18 | 19 | public IReadOnlyList Links { get; set; } = new List(); 20 | 21 | [JsonIgnore] 22 | public IReadOnlyDictionary LinkByLogin { get; set; } = new Dictionary(); 23 | } 24 | #pragma warning restore CS8618 25 | 26 | -------------------------------------------------------------------------------- /DotNet.DocsTools/OspoClientServices/OspoUnauthorizedException.cs: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/dotnet/org-policy/tree/main/src/Microsoft.DotnetOrg.Ospo 2 | 3 | using System.Net; 4 | 5 | namespace Microsoft.DotnetOrg.Ospo; 6 | 7 | [Serializable] 8 | public class OspoUnauthorizedException : OspoException 9 | { 10 | public OspoUnauthorizedException() 11 | { 12 | } 13 | 14 | public OspoUnauthorizedException(string? message) 15 | : base(message) 16 | { 17 | } 18 | 19 | public OspoUnauthorizedException(string? message, Exception? inner) 20 | : base(message, inner) 21 | { 22 | } 23 | 24 | public OspoUnauthorizedException(string? message, HttpStatusCode code) 25 | : base(message, code) 26 | { 27 | } 28 | } -------------------------------------------------------------------------------- /DotNet.DocsTools/Serialization/JsonSerializerOptionsDefaults.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | 3 | namespace DotNetDocs.Tools.Serialization; 4 | 5 | internal static class JsonSerializerOptionsDefaults 6 | { 7 | /// 8 | internal static JsonSerializerOptions Shared { get; } = 9 | new(JsonSerializerDefaults.Web); 10 | } 11 | -------------------------------------------------------------------------------- /DotnetDocsToolsTests/DotnetDocsTools.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /DotnetDocsToolsTests/GraphQLProcessingTests/DefaultBranchTests.cs: -------------------------------------------------------------------------------- 1 | using DotNet.DocsTools.GitHubObjects; 2 | using System.Text.Json; 3 | using Xunit; 4 | 5 | namespace DotnetDocsTools.Tests.GraphQLProcessingTests; 6 | 7 | public class DefaultBranchTests 8 | { 9 | private const string ValidResult = """ 10 | { 11 | "name": "main" 12 | } 13 | """; 14 | 15 | 16 | [Fact] 17 | public void DefaultBranchName_Is_Correct() 18 | { 19 | var variables = new DefaultBranchVariables 20 | { 21 | Organization = "dotnet", 22 | Repository = "docs" 23 | }; 24 | 25 | JsonElement element = JsonDocument.Parse(ValidResult).RootElement; 26 | var issue = DefaultBranch.FromJsonElement(element, variables); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /GitHub.QuerySandbox/GitHub.QuerySandbox.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /GitHub.QuerySandbox/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using System.Text; 2 | 3 | global using GitHub.QuerySandbox.Spinners; 4 | 5 | global using Octokit; 6 | global using Octokit.Internal; 7 | 8 | global using Spectre.Console; 9 | global using SpectreEmoji = Spectre.Console.Emoji; -------------------------------------------------------------------------------- /GitHub.QuerySandbox/Spinners/TimeTravelSpinner.cs: -------------------------------------------------------------------------------- 1 | namespace GitHub.QuerySandbox.Spinners; 2 | 3 | internal sealed class TimeTravelSpinner : Spinner 4 | { 5 | public override TimeSpan Interval => TimeSpan.FromMilliseconds(100); 6 | public override bool IsUnicode => true; 7 | public override IReadOnlyList Frames => new List 8 | { 9 | "🕚 ", 10 | "🕙 ", 11 | "🕘 ", 12 | "🕗 ", 13 | "🕖 ", 14 | "🕕 ", 15 | "🕔 ", 16 | "🕓 ", 17 | "🕒 ", 18 | "🕑 ", 19 | "🕐 ", 20 | "🕛 ", 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /GitHub.QuerySandbox/github-query-sandbox.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.33920.267 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GitHub.QuerySandbox", "GitHub.QuerySandbox.csproj", "{54D4AC77-C0F9-4FA5-A419-39D1B2D96652}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {54D4AC77-C0F9-4FA5-A419-39D1B2D96652}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {54D4AC77-C0F9-4FA5-A419-39D1B2D96652}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {54D4AC77-C0F9-4FA5-A419-39D1B2D96652}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {54D4AC77-C0F9-4FA5-A419-39D1B2D96652}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {D79C8B19-C1D4-4069-9943-BFF249270EC1} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/App.razor: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Not found 8 | 9 |

Sorry, there's nothing at this address.

10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Components/ProgressIndicator.razor: -------------------------------------------------------------------------------- 1 | 
2 |
3 | @Message 4 | 5 |
6 |
7 | 8 | @code { 9 | [Parameter] 10 | public string Message { get; set; } = "🤓 Loading, please wait..."; 11 | } 12 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Extensions/LocalStorageServiceExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace GitHub.RepositoryExplorer.Client.Extensions; 2 | 3 | internal static class LocalStorageServiceExtensions 4 | { 5 | internal static T? TryGetItem(this ILocalStorageService localStorage, string key) 6 | { 7 | try 8 | { 9 | return localStorage.GetItem(key); 10 | } 11 | catch 12 | { 13 | return default; 14 | } 15 | } 16 | 17 | internal static void TrySetItem(this ILocalStorageService localStorage, string key, T value) 18 | { 19 | try 20 | { 21 | localStorage.SetItem(key, value); 22 | } 23 | catch { } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using GitHub.RepositoryExplorer.Client; 2 | global using GitHub.RepositoryExplorer.Client.Components; 3 | global using GitHub.RepositoryExplorer.Client.Options; 4 | global using GitHub.RepositoryExplorer.Client.Services; 5 | global using GitHub.RepositoryExplorer.Models; 6 | global using Microsoft.AspNetCore.Components; 7 | global using Microsoft.AspNetCore.Components.Web; 8 | global using Microsoft.AspNetCore.Components.WebAssembly.Hosting; 9 | global using Microsoft.Extensions.DependencyInjection; 10 | global using Microsoft.Extensions.Options; 11 | global using Microsoft.JSInterop; 12 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/HttpClientNames.cs: -------------------------------------------------------------------------------- 1 | namespace GitHub.RepositoryExplorer.Client; 2 | 3 | static class HttpClientNames 4 | { 5 | internal static string IssuesApi = nameof(IssuesApi); 6 | } 7 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Models/IssueSummary.cs: -------------------------------------------------------------------------------- 1 | public record class IssueSummary 2 | { 3 | public bool IsLoading { get; init; } = true; 4 | 5 | public DateOnly Date { get; init; } 6 | 7 | public IEnumerable Data { get; init; } = 8 | Array.Empty(); 9 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Models/RepoLabels.cs: -------------------------------------------------------------------------------- 1 | public record class RepoLabels 2 | { 3 | public bool IsLoading { get; init; } = true; 4 | 5 | public IssueClassificationModel IssueClassification { get; init; } = new(); 6 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Models/Repository.cs: -------------------------------------------------------------------------------- 1 | public record class Repository( 2 | string? Org, 3 | string? Repo) 4 | { 5 | public bool IsAssigned => Org is { Length: > 0 } && Repo is { Length: > 0 }; 6 | } 7 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Options/IssuesApiOptions.cs: -------------------------------------------------------------------------------- 1 | namespace GitHub.RepositoryExplorer.Client.Options; 2 | 3 | public class IssuesApiOptions 4 | { 5 | public string ServerUrl { get; set; } = null!; 6 | } 7 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Pages/Areas.razor.css: -------------------------------------------------------------------------------- 1 | .clickable-link { 2 | cursor: pointer; 3 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Pages/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | 3 | GitHub Issues | Home 4 | 5 | 6 |

7 | You're repo is configured as: 8 |

 9 |                     
10 |                         @_config.FullyQualifiedOrgAndRepo
11 |                     
12 |                 
13 | 17 |

18 |
19 |
20 | 21 | @code { 22 | private ConfigureRepo _config = null!; 23 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Program.cs: -------------------------------------------------------------------------------- 1 | var builder = WebAssemblyHostBuilder.CreateDefault(args); 2 | builder.RootComponents.Add("#app"); 3 | builder.RootComponents.Add("head::after"); 4 | 5 | if (builder.HostEnvironment.IsDevelopment()) 6 | { 7 | builder.Logging.SetMinimumLevel(LogLevel.Debug); 8 | } 9 | 10 | builder.Services.AddOptions(); 11 | builder.Services.Configure( 12 | builder.Configuration.GetSection(nameof(IssuesApiOptions))); 13 | 14 | builder.Services.AddSingleton(); 15 | 16 | builder.Services.AddHttpClient(); 17 | builder.Services.AddHttpClient( 18 | HttpClientNames.IssuesApi, 19 | (services, client) => 20 | { 21 | var options = 22 | services.GetRequiredService>().Value; 23 | 24 | client.BaseAddress = new Uri(options.ServerUrl); 25 | }); 26 | 27 | builder.Services.AddSingleton(); 28 | builder.Services.AddSingleton(); 29 | builder.Services.AddSingleton(); 30 | builder.Services.AddSingleton(); 31 | builder.Services.AddSingleton(); 32 | builder.Services.AddLocalStorageServices(); 33 | 34 | await builder.Build().RunAsync(); 35 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:65506", 7 | "sslPort": 44398 8 | } 9 | }, 10 | "profiles": { 11 | "GitHub.RepositoryExplorer.Client": { 12 | "commandName": "Project", 13 | "dotnetRunMessages": true, 14 | "launchBrowser": true, 15 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 16 | "applicationUrl": "https://localhost:7299;http://localhost:5299", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | } 20 | }, 21 | "IIS Express": { 22 | "commandName": "IISExpress", 23 | "launchBrowser": true, 24 | "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Services/AppInMemoryStateService.cs: -------------------------------------------------------------------------------- 1 | public sealed class AppInMemoryStateService 2 | { 3 | private Repository? _repoState; 4 | public Repository? RepoState 5 | { 6 | get => _repoState; 7 | set 8 | { 9 | _repoState = value; 10 | NotifyStateChanged(); 11 | } 12 | } 13 | 14 | 15 | public event Action? OnChange; 16 | 17 | private void NotifyStateChanged() => OnChange?.Invoke(); 18 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Services/IssuesClient.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | 3 | namespace GitHub.RepositoryExplorer.Client.Services; 4 | 5 | public sealed class IssuesClient 6 | { 7 | private readonly HttpClient _httpClient; 8 | private readonly Func _encode = 9 | static string (DateOnly date) => HttpUtility.UrlEncode($"{date:o}"); 10 | 11 | public IssuesClient(IHttpClientFactory factory) 12 | { 13 | _httpClient = factory.CreateClient(HttpClientNames.IssuesApi); 14 | } 15 | 16 | public async Task GetIssuesForDateAsync( 17 | Repository state, DateOnly date, IssueClassificationModel model) 18 | { 19 | var (org, repo) = (state.Org, state.Repo); 20 | var route = _encode(date); 21 | try 22 | { 23 | var dailyRecord = 24 | await _httpClient.GetFromJsonAsync( 25 | $"api/issues/{org}/{repo}/{route}"); 26 | 27 | return dailyRecord; 28 | } 29 | catch ( Exception ex ) 30 | { 31 | Console.WriteLine(ex); 32 | return DailyRecordFactory.CreateMissingRecord(date, model, org, repo); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Services/RespositoryLabelsClient.cs: -------------------------------------------------------------------------------- 1 | namespace GitHub.RepositoryExplorer.Client.Services; 2 | 3 | public class RepositoryLabelsClient 4 | { 5 | private readonly HttpClient _httpClient; 6 | 7 | public RepositoryLabelsClient(IHttpClientFactory factory) 8 | { 9 | _httpClient = factory.CreateClient(HttpClientNames.IssuesApi); 10 | } 11 | 12 | public async Task GetRepositoryLabelsAsync(Repository state) 13 | { 14 | var (org, repo) = (state.Org, state.Repo); 15 | var result = 16 | await _httpClient.GetFromJsonAsync( 17 | $"api/repositorylabels/{org}/{repo}"); 18 | 19 | return result; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 |
4 | 7 | 8 |
9 |
10 | About 11 |
12 | 13 |
14 |
15 | @Body 16 |
17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using System.Net.Http.Json 3 | @using Microsoft.AspNetCore.Components.Forms 4 | @using Microsoft.AspNetCore.Components.Routing 5 | @using Microsoft.AspNetCore.Components.Web 6 | @using Microsoft.AspNetCore.Components.Web.Virtualization 7 | @using Microsoft.AspNetCore.Components.WebAssembly.Http 8 | @using Microsoft.JSInterop 9 | @using GitHub.RepositoryExplorer.Client 10 | @using GitHub.RepositoryExplorer.Client.Components 11 | @using GitHub.RepositoryExplorer.Client.Shared 12 | @using GitHub.RepositoryExplorer.Client.Pages 13 | @using ChartJs.Blazor 14 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/wwwroot/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "IssuesApiOptions": { 3 | "ServerUrl": "https://localhost:7039" 4 | } 5 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/wwwroot/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IssuesApiOptions": { 3 | "ServerUrl": "https://github-explorer-web-api.azurewebsites.net" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/wwwroot/css/open-iconic/ICON-LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Waybury 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/docs-tools/e88a4c229f2fc2dbe5cfa3ffabbcef8489ffba50/GitHub.RepositoryExplorer.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.eot -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/docs-tools/e88a4c229f2fc2dbe5cfa3ffabbcef8489ffba50/GitHub.RepositoryExplorer.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.otf -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/docs-tools/e88a4c229f2fc2dbe5cfa3ffabbcef8489ffba50/GitHub.RepositoryExplorer.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/docs-tools/e88a4c229f2fc2dbe5cfa3ffabbcef8489ffba50/GitHub.RepositoryExplorer.Client/wwwroot/css/open-iconic/font/fonts/open-iconic.woff -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/docs-tools/e88a4c229f2fc2dbe5cfa3ffabbcef8489ffba50/GitHub.RepositoryExplorer.Client/wwwroot/favicon.ico -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Client/wwwroot/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/docs-tools/e88a4c229f2fc2dbe5cfa3ffabbcef8489ffba50/GitHub.RepositoryExplorer.Client/wwwroot/icon-192.png -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Functions/Configuration/RepositoriesConfig.cs: -------------------------------------------------------------------------------- 1 | namespace GitHub.RepositoryExplorer.Functions.Configuration; 2 | 3 | public class RepositoriesConfig 4 | { 5 | public List Repositories { get; set; } = new(); 6 | } 7 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Functions/Configuration/RepositoryConfig.cs: -------------------------------------------------------------------------------- 1 | namespace GitHub.RepositoryExplorer.Functions.Configuration; 2 | 3 | public class RepositoryConfig 4 | { 5 | public string? OrganizationName { get; set; } 6 | public string? RepositoryName { get; set; } 7 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Functions/Properties/serviceDependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "appInsights1": { 4 | "type": "appInsights" 5 | }, 6 | "storage1": { 7 | "type": "storage", 8 | "connectionId": "AzureWebJobsStorage" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Functions/Properties/serviceDependencies.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "appInsights1": { 4 | "type": "appInsights.sdk" 5 | }, 6 | "storage1": { 7 | "type": "storage.emulator", 8 | "connectionId": "AzureWebJobsStorage" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Functions/README.md: -------------------------------------------------------------------------------- 1 | # Functions App for GitHub.RepositoryExplorer 2 | 3 | Function app built using the Azure Function SDK v4 and .NET 6. This app contains timer triggered functions that will retrieve and store daily issue counts from the configured GitHub repositories. 4 | 5 | List of repositories configured in `appsettings.json`. 6 | 7 | Create a `local.settings.json` file with the following contents: 8 | 9 | { 10 | "IsEncrypted": false, 11 | "Values": { 12 | "AzureWebJobsStorage": "UseDevelopmentStorage=true", 13 | "FUNCTIONS_WORKER_RUNTIME": "dotnet", 14 | "GitHubKey": "YOUR GITHUB PERSONAL ACCESS TOKEN HERE", 15 | "RepositoryOptions__CosmosConnectionString": "YOUR COSMOS DB CONNECTION STRING HERE", 16 | "RepositoryOptions__DatabaseId": "IssueStatistics", 17 | "RepositoryOptions__ContainerId": "DailyStatistics" 18 | } 19 | } 20 | 21 | ## Running Function Manually 22 | 23 | When doing local development, to run a TimerTrigger function manually, send a POST request to the folllowing URL: 24 | 25 | `http://localhost:7071/admin/functions/{FunctionName}` 26 | 27 | with a JSON body: 28 | 29 | ``` 30 | { "input": "test" } 31 | ``` 32 | 33 | Example: 34 | `POST http://localhost:7071/admin/functions/CaptureDailyIssueCountsFunction` 35 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Functions/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Functions/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "RepositoriesConfig": { 3 | "Repositories": [ 4 | { 5 | "OrganizationName": "dotnet", 6 | "RepositoryName": "docs" 7 | } 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Functions/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingSettings": { 6 | "isEnabled": true, 7 | "excludedTypes": "Request" 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Models/GitHub.RepositoryExplorer.Models.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Always 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Models/IssuesSnapshot.cs: -------------------------------------------------------------------------------- 1 | namespace GitHub.RepositoryExplorer.Models; 2 | 3 | /// 4 | /// A snapshot representation of issues. 5 | /// 6 | /// The product (ms.prod) value. 7 | /// The technology (ms.technology) value. 8 | /// The priority value, for example; Pri1. 9 | /// The product (ms.prod) value. 10 | /// The number of issues for a given snapshot. 11 | /// The date of the snapshot. 12 | /// The interval between snapshot counts, defaults to one day. 13 | public readonly record struct IssuesSnapshot( 14 | string? Product, 15 | string? Technology, 16 | string? Priority, 17 | string? Classification, 18 | int[] DailyCount, 19 | string StartDate, 20 | int Interval = 1) 21 | { 22 | public static implicit operator SnapshotKey(IssuesSnapshot snapshot) => 23 | new ( 24 | Product: snapshot.Product, 25 | Technology: snapshot.Technology, 26 | Priority: snapshot.Priority, 27 | Classification: snapshot.Classification); 28 | 29 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Models/SnapshotKey.cs: -------------------------------------------------------------------------------- 1 | namespace GitHub.RepositoryExplorer.Models; 2 | 3 | public readonly record struct SnapshotKey( 4 | string? Product, 5 | string? Technology, 6 | string? Priority, 7 | string? Classification); 8 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.Services/GitHub.RepositoryExplorer.Services.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 1.1.0.0 8 | 1.1.0.0 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.WebApi/CorsPolicy.cs: -------------------------------------------------------------------------------- 1 | namespace GitHub.RepositoryExplorer.WebApi; 2 | 3 | static class CorsPolicy 4 | { 5 | internal const string Name = nameof(Name); 6 | } 7 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.WebApi/GitHub.RepositoryExplorer.WebApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net9.0 4 | enable 5 | enable 6 | 7d02fdaa-bfe2-4c8f-aee9-77abea14057c 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.WebApi/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using GitHub.RepositoryExplorer.Models; 2 | global using GitHub.RepositoryExplorer.Services; 3 | global using GitHub.RepositoryExplorer.WebApi; 4 | global using Microsoft.AspNetCore.Cors; 5 | global using Microsoft.AspNetCore.Mvc; 6 | global using Microsoft.Azure.CosmosRepository; 7 | global using System.Net.Mime; 8 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.WebApi/Program.cs: -------------------------------------------------------------------------------- 1 | [assembly: ApiController] 2 | 3 | var builder = WebApplication.CreateBuilder(args); 4 | 5 | builder.Services.AddCors( 6 | options => options.AddPolicy( 7 | CorsPolicy.Name, 8 | policy => policy.WithOrigins("https://localhost:7299") 9 | .AllowAnyMethod() 10 | .AllowAnyHeader() 11 | .AllowCredentials())); 12 | 13 | builder.Services.AddMemoryCache(); 14 | builder.Services.AddSingleton(); 15 | builder.Services.AddResponseCaching(); 16 | builder.Services.AddControllers(); 17 | builder.Services.AddEndpointsApiExplorer(); 18 | builder.Services.AddSwaggerGen(); 19 | builder.Services.AddApplicationInsightsTelemetry(); 20 | builder.Services.AddCosmosRepository(); 21 | 22 | var app = builder.Build(); 23 | if (app.Environment.IsDevelopment()) 24 | { 25 | app.UseSwagger(); 26 | app.UseSwaggerUI(); 27 | } 28 | 29 | app.UseResponseCaching(); 30 | app.UseHttpsRedirection(); 31 | app.UseRouting(); 32 | app.UseCors(CorsPolicy.Name); 33 | app.MapControllers(); 34 | app.Run(); 35 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.WebApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:53612", 8 | "sslPort": 44355 9 | } 10 | }, 11 | "profiles": { 12 | "GitHub.RepositoryExplorer.WebApi": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "https://localhost:7039;http://localhost:5261", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "IIS Express": { 23 | "commandName": "IISExpress", 24 | "launchBrowser": true, 25 | "launchUrl": "swagger", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.WebApi/Properties/serviceDependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "appInsights1": { 4 | "type": "appInsights" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.WebApi/Properties/serviceDependencies.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "appInsights1": { 4 | "type": "appInsights.sdk" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.WebApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /GitHub.RepositoryExplorer.WebApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*", 9 | "RepositoryOptions" : { 10 | "CosmosConnectionString": "YOUR COSMOS DB CONNECTION STRING IN USER SECRETS", 11 | "DatabaseId": "IssueStatistics", 12 | "ContainerId": "DailyStatistics" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /IssueCloser/BulkCloseConfig.cs: -------------------------------------------------------------------------------- 1 | namespace IssueCloser; 2 | 3 | /// 4 | /// The data object for close config records 5 | /// 6 | public record BulkCloseConfig(CloseCriteria Criteria, int AgeInMonths); 7 | -------------------------------------------------------------------------------- /IssueCloser/CloseCriteria.cs: -------------------------------------------------------------------------------- 1 | namespace IssueCloser; 2 | 3 | /// 4 | /// The data record for matching values against close criteria. 5 | /// 6 | public record CloseCriteria(Priority PriLabel, bool HasDocIssue, bool IsInternal); 7 | -------------------------------------------------------------------------------- /IssueCloser/IssueCloser.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | 2.0.0.0 9 | 2.0.0.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | PreserveNewest 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE-CODE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) Microsoft Corporation 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to deal in the Software without restriction, 6 | including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 7 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial 11 | portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 15 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 16 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 17 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /PackageIndexer/CsvEntry.cs: -------------------------------------------------------------------------------- 1 | namespace PackageIndexer; 2 | 3 | public sealed class CsvEntry 4 | { 5 | public static CsvEntry Create(string packageNumber, string packageName, string packageVersion) 6 | { 7 | return new CsvEntry(packageNumber, packageName, packageVersion); 8 | } 9 | 10 | private CsvEntry(string packageNumber, string packageName, string packageVersion) 11 | { 12 | PackageNumber = packageNumber; 13 | PackageName = packageName; 14 | PackageVersion = packageVersion; 15 | } 16 | 17 | public string PackageNumber { get; set; } 18 | public string PackageName { get; set; } 19 | public string PackageVersion { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /PackageIndexer/FindProjectsWithDocs.ps1: -------------------------------------------------------------------------------- 1 | Get-ChildItem -Path "C:\path\to\runtime\src\libraries" -Recurse -Filter "*.csproj" -File | 2 | Where-Object { $_.FullName -notlike "*\ref\*" -and $_.FullName -notlike "*\tests\*" -and $_.FullName -notlike "*\gen\*" -and $_.FullName -notlike "*\shims\*" -and $_.FullName -notlike "*\tools\*" -and $_.FullName -notlike "*\System.Private*\*" -and $_.FullName -notlike "*\Fuzzing\*" -and $_.FullName -notlike "*\externals.csproj" -and $_.FullName -notlike "*\Microsoft.NETCore.Platforms\*" -and $_.BaseName -notlike "System.Threading.RateLimiting" -and $_.BaseName -notlike "Microsoft.XmlSerializer.Generator" } | 3 | ForEach-Object { 4 | $content = Get-Content -Path $_.FullName -Raw 5 | if ($content -notmatch "UseCompilerGeneratedDocXmlFile") { 6 | $_.BaseName 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /PackageIndexer/NuGet/NuGetFeeds.cs: -------------------------------------------------------------------------------- 1 | namespace PackageIndexer; 2 | 3 | public static class NuGetFeeds 4 | { 5 | public static string NuGetOrg => "https://api.nuget.org/v3/index.json"; 6 | public static string NightlyDotnet7 => "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json"; 7 | public static string NightlyDotnet8 => "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8/nuget/v3/index.json"; 8 | public static string NightlyDotnet9 => "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9/nuget/v3/index.json"; 9 | public static string NightlyXamarin => "https://pkgs.dev.azure.com/azure-public/vside/_packaging/xamarin-impl/nuget/v3/index.json"; 10 | public static string NightlyLatest => NightlyDotnet9; 11 | } -------------------------------------------------------------------------------- /PackageIndexer/PackageEntry.cs: -------------------------------------------------------------------------------- 1 | namespace PackageIndexer; 2 | 3 | public sealed class PackageEntry 4 | { 5 | public static PackageEntry Create(string id, string version, string repo, IList frameworks) 6 | { 7 | return new PackageEntry(id, version, repo, frameworks); 8 | } 9 | 10 | private PackageEntry(string id, string version, string repo, IList frameworks) 11 | { 12 | Name = id; 13 | Version = version; 14 | Repository = repo; 15 | Frameworks = frameworks; 16 | } 17 | 18 | //public Guid Fingerprint { get; } 19 | public string Name { get; } 20 | public string Version { get; } 21 | public string Repository { get; } 22 | public IList Frameworks { get; } 23 | 24 | public void Write(Stream stream) 25 | { 26 | XmlEntryFormat.WritePackageEntry(stream, this); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /PackageIndexer/PackageIndexer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # .NET Docs: Tools and GitHub Actions 2 | 3 | [![CodeQL](https://github.com/dotnet/docs-tools/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/dotnet/docs-tools/actions/workflows/codeql-analysis.yml) [![Build docs-verifier](https://github.com/dotnet/docs-tools/actions/workflows/build-docs-verifier.yml/badge.svg)](https://github.com/dotnet/docs-tools/actions/workflows/build-docs-verifier.yml) [![dotnet build and test](https://github.com/dotnet/docs-tools/actions/workflows/dotnet-build-validation.yml/badge.svg)](https://github.com/dotnet/docs-tools/actions/workflows/dotnet-build-validation.yml) [![node build and test](https://github.com/dotnet/docs-tools/actions/workflows/node-build-validation.yml/badge.svg)](https://github.com/dotnet/docs-tools/actions/workflows/node-build-validation.yml) [![quest import](https://github.com/dotnet/docs-tools/actions/workflows/quest.yml/badge.svg)](https://github.com/dotnet/docs-tools/actions/workflows/quest.yml) 4 | 5 | This repo contains GitHub Actions and other tools that the .NET docs team uses to maintain quality. Many of the tools are designed to be invoked on DocFx repositories. 6 | 7 | For information about the code of conduct, see [Code of conduct](CODE-OF-CONDUCT.md). 8 | -------------------------------------------------------------------------------- /RepoMan/Actions/CloseObject.cs: -------------------------------------------------------------------------------- 1 | namespace RepoMan.Actions; 2 | 3 | public sealed class CloseObject: IRunnerItem 4 | { 5 | public CloseObject() 6 | { 7 | } 8 | 9 | public async Task Run(State state) 10 | { 11 | await GithubCommand.Close(state); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /RepoMan/Actions/Comment.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using YamlDotNet.RepresentationModel; 3 | 4 | namespace RepoMan.Actions; 5 | 6 | public sealed class Comment : IRunnerItem 7 | { 8 | private readonly string _comment; 9 | private readonly string _value; 10 | 11 | public Comment(YamlNode node, State state) 12 | { 13 | _comment = node.ToString(); 14 | } 15 | 16 | public async Task Run(State state) 17 | { 18 | state.Logger.LogInformation($"Adding comment"); 19 | state.Logger.LogDebugger(_comment); 20 | await GithubCommand.AddComment(_comment, state); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /RepoMan/Actions/ProductTechLabels.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace RepoMan.Actions; 4 | 5 | public sealed class SetSvcSubSvcLabels: IRunnerItem 6 | { 7 | public SetSvcSubSvcLabels() 8 | { 9 | } 10 | 11 | public async Task Run(State state) 12 | { 13 | state.Logger.LogInformation($"Adding service and subservice labels"); 14 | 15 | if (state.Variables.ContainsKey("ms.service")) 16 | state.Operations.LabelsAdd.Add($"{state.Variables["ms.service"]}/svc"); 17 | 18 | if (state.Variables.ContainsKey("ms.subservice")) 19 | state.Operations.LabelsAdd.Add($"{state.Variables["ms.subservice"]}/subsvc"); 20 | 21 | await Task.CompletedTask; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /RepoMan/Checks/CommentBody.cs: -------------------------------------------------------------------------------- 1 | using YamlDotNet.RepresentationModel; 2 | 3 | namespace RepoMan.Checks; 4 | 5 | public sealed class CommentBody : ICheck 6 | { 7 | public string RegEx { get; } 8 | 9 | public CommentBody(YamlMappingNode node, State state) 10 | { 11 | RegEx = node["value"].ToString(); 12 | state.Logger.LogDebugger($"BUILD: comment-body {RegEx}"); 13 | } 14 | 15 | public async Task Run(State state) 16 | { 17 | state.Logger.LogDebugger($"RUN: CommentBody regex check '{RegEx}'"); 18 | if (Utilities.MatchRegex(RegEx, state.IssuePrBody ?? "", state)) 19 | { 20 | state.Logger.LogDebugger($"RUN: CommentBody pass"); 21 | return await Task.FromResult(true); 22 | } 23 | 24 | state.Logger.LogDebugger($"RUN: CommentBody fail"); 25 | return await Task.FromResult(false); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /RepoMan/Checks/DocMetadata.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using YamlDotNet.RepresentationModel; 3 | 4 | namespace RepoMan.Checks; 5 | 6 | public sealed class DocMetadata : ICheck 7 | { 8 | public string Name { get; } 9 | public string Value { get; } 10 | 11 | public DocMetadata(YamlMappingNode node, State state) 12 | { 13 | state.Logger.LogDebugger($"BUILD: Check-metadata-comment"); 14 | 15 | Name = node["name"].ToString(); 16 | Value = node["value"].ToString(); 17 | 18 | state.Logger.LogTrace($"BUILD: Name: {Name} Value: {Value}"); 19 | } 20 | 21 | public async Task Run(State state) 22 | { 23 | bool result = false; 24 | 25 | state.Logger.LogInformation($"Evaluating comment metadata: {Name} for {Value}"); 26 | 27 | if (state.DocIssueMetadata.ContainsKey(Name)) 28 | result = Utilities.MatchRegex(Value, state.DocIssueMetadata[Name], state); 29 | 30 | if (result) 31 | state.Logger.LogInformation($"PASS"); 32 | else 33 | state.Logger.LogInformation($"FAIL"); 34 | 35 | return await Task.FromResult(result); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /RepoMan/Checks/DocMetadataExists.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace RepoMan.Checks; 4 | 5 | public sealed class DocMetadataExists : ICheck 6 | { 7 | public DocMetadataExists(State state) 8 | { 9 | state.Logger.LogDebugger($"BUILD: Check-metadata-exists"); 10 | } 11 | 12 | public async Task Run(State state) 13 | { 14 | state.Logger.LogInformation($"Evaluating if doc metadata exists"); 15 | 16 | bool result = state.DocIssueMetadata.Count != 0; 17 | 18 | if (result) 19 | state.Logger.LogInformation($"PASS"); 20 | else 21 | state.Logger.LogInformation($"FAIL"); 22 | 23 | return await Task.FromResult(result); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /RepoMan/Checks/DocNewMetadataExists.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace RepoMan.Checks; 4 | 5 | public sealed class DocNewMetadataExists : ICheck 6 | { 7 | public DocNewMetadataExists(State state) 8 | { 9 | state.Logger.LogDebugger($"BUILD: Check-newmetadata-exists"); 10 | } 11 | 12 | public async Task Run(State state) 13 | { 14 | state.Logger.LogInformation($"Evaluating if doc v2 metadata exists"); 15 | 16 | if (state.IsV2Metadata) 17 | state.Logger.LogInformation($"PASS"); 18 | else 19 | state.Logger.LogInformation($"FAIL"); 20 | 21 | return await Task.FromResult(state.IsV2Metadata); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /RepoMan/Checks/ForceFail.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace RepoMan.Checks; 4 | 5 | public sealed class ForceFail : ICheck 6 | { 7 | public ForceFail() 8 | { 9 | 10 | } 11 | 12 | public async Task Run(State state) 13 | { 14 | state.Logger.LogInformation($"Check ForceFail"); 15 | 16 | return await Task.FromResult(false); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /RepoMan/Checks/ICheck.cs: -------------------------------------------------------------------------------- 1 | namespace RepoMan.Checks; 2 | 3 | public interface ICheck 4 | { 5 | Task Run(State state); 6 | } 7 | -------------------------------------------------------------------------------- /RepoMan/Checks/IsDraft.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using YamlDotNet.RepresentationModel; 3 | 4 | namespace RepoMan.Checks; 5 | 6 | public sealed class IsDraft : ICheck 7 | { 8 | public bool Condition { get; } 9 | 10 | public IsDraft(YamlMappingNode node, State state) 11 | { 12 | state.Logger.LogDebugger($"BUILD: IsDraft"); 13 | Condition = Convert.ToBoolean(node["value"].ToString()); 14 | state.Logger.LogTrace($"BUILD: - {Condition}"); 15 | } 16 | 17 | public async Task Run(State state) 18 | { 19 | state.Logger.LogInformation($"Check IsDraft: {Condition}"); 20 | 21 | if (!state.IsPullRequest) 22 | { 23 | state.Logger.LogError("Tried to check IsDraft on non-PR"); 24 | return await Task.FromResult(false); 25 | } 26 | 27 | bool result = state.PullRequest?.Draft == Condition; 28 | 29 | if (result) 30 | state.Logger.LogInformation($"PASS"); 31 | else 32 | state.Logger.LogInformation($"FAIL"); 33 | 34 | return await Task.FromResult(result); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /RepoMan/Checks/Query.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using YamlDotNet.RepresentationModel; 3 | 4 | namespace RepoMan.Checks; 5 | 6 | public sealed class Query : ICheck 7 | { 8 | public string Value { get; } 9 | 10 | public Query(YamlMappingNode node, State state) 11 | { 12 | Value = node["value"].ToString(); 13 | state.Logger.LogDebugger($"BUILD: Check-Query"); 14 | state.Logger.LogTrace($"BUILD: {Value}"); 15 | } 16 | 17 | public async Task Run(State state) 18 | { 19 | state.Logger.LogInformation($"Evaluating: {Value}"); 20 | 21 | bool result = Utilities.TestStateJMES(Value, state); 22 | 23 | if (result) 24 | state.Logger.LogInformation($"PASS"); 25 | else 26 | state.Logger.LogInformation($"FAIL"); 27 | 28 | return await Task.FromResult(result); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /RepoMan/Checks/Variable.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using YamlDotNet.RepresentationModel; 3 | 4 | namespace RepoMan.Checks; 5 | 6 | public sealed class Variable : ICheck 7 | { 8 | public string Name { get; } 9 | public string Value { get; } 10 | 11 | public Variable(YamlMappingNode node, State state) 12 | { 13 | state.Logger.LogDebugger($"BUILD: Variable"); 14 | Name = node["name"].ToString(); 15 | Value = node["value"].ToString(); 16 | state.Logger.LogTrace($"BUILD: - {Name}={Value}"); 17 | } 18 | 19 | public async Task Run(State state) 20 | { 21 | state.Logger.LogInformation($"Check variable: {Name}={Value}"); 22 | 23 | bool result = state.Variables.ContainsKey(Name) && state.Variables[Name] == Value; 24 | 25 | if (result) 26 | state.Logger.LogInformation($"PASS"); 27 | else 28 | state.Logger.LogInformation($"FAIL"); 29 | 30 | return await Task.FromResult(result); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /RepoMan/ILoggerExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace RepoMan; 4 | 5 | public static class ILoggerExtensions 6 | { 7 | public static void LogDebugger(this ILogger logger, string msg, params object[] args) 8 | { 9 | if (Environment.GetEnvironmentVariable("logdebug", EnvironmentVariableTarget.Process) != null) 10 | logger.LogInformation(msg, args); 11 | else 12 | logger.LogDebug(msg, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /RepoMan/IRunnerItem.cs: -------------------------------------------------------------------------------- 1 | namespace RepoMan; 2 | 3 | public interface IRunnerItem 4 | { 5 | Task Run(State state); 6 | } 7 | -------------------------------------------------------------------------------- /RepoMan/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Azure.Functions.Worker; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Hosting; 4 | 5 | var host = new HostBuilder() 6 | .ConfigureFunctionsWebApplication() 7 | .ConfigureServices(services => { 8 | services.AddApplicationInsightsTelemetryWorkerService(); 9 | services.ConfigureFunctionsApplicationInsights(); 10 | }) 11 | .Build(); 12 | 13 | host.Run(); 14 | -------------------------------------------------------------------------------- /RepoMan/Properties/serviceDependencies.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "storage1": { 4 | "type": "storage", 5 | "connectionId": "AzureWebJobsStorage" 6 | }, 7 | "appInsights1": { 8 | "type": "appInsights", 9 | "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING", 10 | "dynamicId": null 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /RepoMan/Properties/serviceDependencies.local.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "appInsights1": { 4 | "type": "appInsights.sdk" 5 | }, 6 | "storage1": { 7 | "type": "storage.emulator", 8 | "connectionId": "AzureWebJobsStorage" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /RepoMan/Properties/serviceDependencies.repoman - Zip Deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "appInsights1": { 4 | "secretStore": "AzureAppSettings", 5 | "resourceId": "/subscriptions/[parameters('subscriptionId')]/resourceGroups/[parameters('resourceGroupName')]/providers/microsoft.insights/components/repomanai", 6 | "type": "appInsights.azure", 7 | "connectionId": "APPLICATIONINSIGHTS_CONNECTION_STRING", 8 | "dynamicId": null 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /RepoMan/RequestType.cs: -------------------------------------------------------------------------------- 1 | namespace RepoMan; 2 | 3 | public enum RequestType 4 | { 5 | PullRequest, 6 | Issue, 7 | Comment 8 | } 9 | -------------------------------------------------------------------------------- /RepoMan/Types.cs: -------------------------------------------------------------------------------- 1 | namespace RepoMan; 2 | 3 | public enum RunnerItemTypes 4 | { 5 | Check, 6 | Label, 7 | Milestone, 8 | Project, 9 | Comment, 10 | Files, 11 | Issue, 12 | PullRquest, 13 | Variable, 14 | Assignee, 15 | Reviewer, 16 | Predefined, 17 | Close, 18 | Reopen, 19 | SvcSubSvcLabels 20 | } 21 | 22 | public enum RunnerItemSubTypes 23 | { 24 | Add, 25 | Remove, 26 | Set 27 | } 28 | -------------------------------------------------------------------------------- /RepoMan/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingSettings": { 6 | "isEnabled": true, 7 | "excludedTypes": "Request" 8 | }, 9 | "enableLiveMetricsFilters": true 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /RepoMan/readme.md: -------------------------------------------------------------------------------- 1 | Source code for the github issue labeler used on https://github.com/dotnet/docs/ -------------------------------------------------------------------------------- /Sandbox/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.DotnetOrg.Ospo; 2 | 3 | var azureAccessToken = Environment.GetEnvironmentVariable("AZURE_ACCESS_TOKEN"); 4 | 5 | var client = new OspoClient(azureAccessToken!, true); 6 | 7 | var link = client != null ? await client.GetAsync("IEvangelist") : null; 8 | 9 | if (link is not null) 10 | { 11 | _ = link; 12 | } 13 | -------------------------------------------------------------------------------- /Sandbox/Sandbox.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SmallRepo/SmallRepo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SmallRepo/action.yml: -------------------------------------------------------------------------------- 1 | name: Small test case 2 | description: Small Test case against the OSPO REST API 3 | author: 'Bill Wagner' 4 | branding: 5 | icon: refresh-cw 6 | color: purple 7 | 8 | runs: 9 | using: docker 10 | image: ../smalltest.Dockerfile 11 | -------------------------------------------------------------------------------- /ThirdPartyNotices.md: -------------------------------------------------------------------------------- 1 | ## Legal Notices 2 | Microsoft and any contributors grant you a license to the Microsoft documentation and other content 3 | in this repository under the [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode), 4 | see the [LICENSE](LICENSE) file, and grant you a license to any code in the repository under the [MIT License](https://opensource.org/licenses/MIT), see the 5 | [LICENSE-CODE](LICENSE-CODE) file. 6 | 7 | Microsoft, Windows, Microsoft Azure and/or other Microsoft products and services referenced in the documentation 8 | may be either trademarks or registered trademarks of Microsoft in the United States and/or other countries. 9 | The licenses for this project do not grant you rights to use any Microsoft names, logos, or trademarks. 10 | Microsoft's general trademark guidelines can be found at http://go.microsoft.com/fwlink/?LinkID=254653. 11 | 12 | Privacy information can be found at https://privacy.microsoft.com/en-us/ 13 | 14 | Microsoft and any contributors reserve all others rights, whether under their respective copyrights, patents, 15 | or trademarks, whether by implication, estoppel or otherwise. -------------------------------------------------------------------------------- /WhatsNew.Cli/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-dotnettools.csharp" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /WhatsNew.Cli/nuget/images/docs-logo-ms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/docs-tools/e88a4c229f2fc2dbe5cfa3ffabbcef8489ffba50/WhatsNew.Cli/nuget/images/docs-logo-ms.png -------------------------------------------------------------------------------- /WhatsNew.Infrastructure.Tests/assets/MicrosoftDocs/azure-devops-docs-pr.json: -------------------------------------------------------------------------------- 1 | { 2 | "docSetProductName": "", 3 | "rootDirectory": "docs/", 4 | "docLinkSettings": { 5 | "linkFormat": "relative", 6 | "relativeLinkPrefix": "/azure/devops/" 7 | }, 8 | "inclusionCriteria": { 9 | "minAdditionsToFile": 62 10 | }, 11 | "areas": [ 12 | { 13 | "names": [ "artifacts" ], 14 | "heading": "Artifacts" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /WhatsNew.Infrastructure.Tests/assets/MicrosoftDocs/cpp-docs-pr.json: -------------------------------------------------------------------------------- 1 | { 2 | "docSetProductName": "C++, C, and Assembler", 3 | "rootDirectory": "docs/", 4 | "docLinkSettings": { 5 | "linkFormat": "relative", 6 | "relativeLinkPrefix": "/cpp/" 7 | }, 8 | "inclusionCriteria": { 9 | "minAdditionsToFile": 10, 10 | "omitPullRequestTitles": true 11 | }, 12 | "areas": [] 13 | } 14 | -------------------------------------------------------------------------------- /WhatsNew.Infrastructure.Tests/assets/dotnet/AspNetCore.Docs.json: -------------------------------------------------------------------------------- 1 | { 2 | "docSetProductName": "ASP.NET Core", 3 | "rootDirectory": "", 4 | "docLinkSettings": { 5 | "linkFormat": "xref" 6 | }, 7 | "areas": [ 8 | { 9 | "names": [ "azure" ], 10 | "heading": "Azure" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /WhatsNew.Infrastructure.Tests/assets/dotnet/docs.json: -------------------------------------------------------------------------------- 1 | { 2 | "docSetProductName": ".NET", 3 | "rootDirectory": "docs/", 4 | "docLinkSettings": { 5 | "linkFormat": "relative" 6 | }, 7 | "inclusionCriteria": { 8 | }, 9 | "areas": [ 10 | { 11 | "names": [ "architecture" ], 12 | "heading": "Architecture guides" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /WhatsNew.Infrastructure.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", 3 | "methodDisplayOptions": "replaceUnderscoreWithSpace" 4 | } 5 | -------------------------------------------------------------------------------- /WhatsNew.Infrastructure/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace WhatsNew.Infrastructure; 2 | 3 | /// 4 | /// Constants used throughout the what's new solution's projects. 5 | /// 6 | public static class Constants 7 | { 8 | /// 9 | /// The directory name in the WhatsNew.Infrastructure project which stores the 10 | /// JSON configuration files for each docset. 11 | /// 12 | public const string ConfigurationDirectory = "Configuration"; 13 | 14 | /// 15 | /// The name of the default directory to which the generated Markdown file is 16 | /// written. 17 | /// 18 | public const string MarkdownFileDirectoryName = "whatsnew"; 19 | 20 | /// 21 | /// The suffix used to indicate a private GitHub repository. 22 | /// 23 | public const string PrivateRepoNameSuffix = "-pr"; 24 | } 25 | -------------------------------------------------------------------------------- /WhatsNew.Infrastructure/Models/DocLinkSettings.cs: -------------------------------------------------------------------------------- 1 | namespace WhatsNew.Infrastructure.Models; 2 | 3 | /// 4 | /// Encapsulates the settings that control the construction of doc 5 | /// links in the generated Markdown file. 6 | /// 7 | public class DocLinkSettings 8 | { 9 | /// 10 | /// The link format to use for links to docs appearing in the 11 | /// generated Markdown file. 12 | /// 13 | public LinkFormat LinkFormat { get; init; } 14 | 15 | /// 16 | /// The path that prefixes the doc link. 17 | /// 18 | /// 19 | /// This property is required when 20 | /// is . 21 | /// 22 | /// /dotnet/ 23 | public string? RelativeLinkPrefix { get; init; } 24 | } 25 | -------------------------------------------------------------------------------- /WhatsNew.Infrastructure/Models/NavigationDetails.cs: -------------------------------------------------------------------------------- 1 | namespace WhatsNew.Infrastructure.Models; 2 | 3 | /// 4 | /// This class defines the properties needed to update the TOC.YML and Index.YML files. 5 | /// 6 | /// 7 | /// These properties are used when you run the tool to create a PR for 8 | /// the what's new documents. 9 | /// 10 | public class NavigationDetails 11 | { 12 | /// 13 | /// Maximum number of articles live in the TOC. 14 | /// 15 | public int MaximumNumberOfArticles { get; set; } 16 | 17 | /// 18 | /// The name of the parent node in the TOC. 19 | /// 20 | public string TocParentNode { get; set; } = default!; 21 | 22 | /// 23 | /// Path from the root of the repository to the toc to modify 24 | /// 25 | public string RepoTocFolder { get; set; } = default!; 26 | 27 | /// 28 | /// The name of the parent node in the TOC. 29 | /// 30 | public string IndexParentNode { get; set; } = default!; 31 | 32 | /// 33 | /// Path from the root of the repository to the toc to modify 34 | /// 35 | public string RepoIndexFolder { get; set; } = default!; 36 | } 37 | -------------------------------------------------------------------------------- /WhatsNew.Infrastructure/Models/RepositoryArea.cs: -------------------------------------------------------------------------------- 1 | namespace WhatsNew.Infrastructure.Models; 2 | 3 | /// 4 | /// Represents a name-value pair, where represents the 5 | /// directory name(s) within the repo and represents the 6 | /// heading text corresponding to that directory. 7 | /// 8 | public class RepositoryArea 9 | { 10 | /// 11 | /// A collection of directory names in the GitHub repository. 12 | /// 13 | public IEnumerable Names { get; init; } = null!; 14 | 15 | /// 16 | /// The heading text for the area/directory. 17 | /// 18 | public string Heading { get; init; } = null!; 19 | } 20 | -------------------------------------------------------------------------------- /WhatsNew.Infrastructure/WhatsNew.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | true 8 | 3.1.0.0 9 | 3.1.0.0 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /XmlDocConflictResolver/Docs/APIKind.cs: -------------------------------------------------------------------------------- 1 | internal enum APIKind 2 | { 3 | Type, 4 | Member 5 | } 6 | -------------------------------------------------------------------------------- /XmlDocConflictResolver/Docs/DocsAssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | internal class DocsAssemblyInfo 4 | { 5 | private readonly XElement _xEAssemblyInfo; 6 | public string AssemblyName => XmlHelper.GetChildElementValue(_xEAssemblyInfo, "AssemblyName"); 7 | 8 | private List? _assemblyVersions; 9 | public List AssemblyVersions 10 | { 11 | get 12 | { 13 | if (_assemblyVersions == null) 14 | { 15 | _assemblyVersions = _xEAssemblyInfo.Elements("AssemblyVersion").Select(x => XmlHelper.GetNodesInPlainText(x)).ToList(); 16 | } 17 | return _assemblyVersions; 18 | } 19 | } 20 | 21 | public DocsAssemblyInfo(XElement xeAssemblyInfo) 22 | { 23 | _xEAssemblyInfo = xeAssemblyInfo; 24 | } 25 | 26 | public override string ToString() => AssemblyName; 27 | } -------------------------------------------------------------------------------- /XmlDocConflictResolver/Docs/DocsMemberSignature.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | internal class DocsMemberSignature 4 | { 5 | private readonly XElement XEMemberSignature; 6 | 7 | public string Language => XmlHelper.GetAttributeValue(XEMemberSignature, "Language"); 8 | public string Value => XmlHelper.GetAttributeValue(XEMemberSignature, "Value"); 9 | 10 | public DocsMemberSignature(XElement xeMemberSignature) 11 | { 12 | XEMemberSignature = xeMemberSignature; 13 | } 14 | } -------------------------------------------------------------------------------- /XmlDocConflictResolver/Docs/DocsParam.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | internal class DocsParam 4 | { 5 | private readonly XElement _xEDocsParam; 6 | 7 | public IDocsAPI ParentAPI 8 | { 9 | get; private set; 10 | } 11 | 12 | public string Name => XmlHelper.GetAttributeValue(_xEDocsParam, "name"); 13 | public string Value => XmlHelper.GetNodesInPlainText(_xEDocsParam); 14 | 15 | public DocsParam(IDocsAPI parentAPI, XElement xeDocsParam) 16 | { 17 | ParentAPI = parentAPI; 18 | _xEDocsParam = xeDocsParam; 19 | } 20 | 21 | public override string ToString() => Name; 22 | } 23 | -------------------------------------------------------------------------------- /XmlDocConflictResolver/Docs/DocsRelated.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | internal class DocsRelated 4 | { 5 | private readonly XElement _xERelatedArticle; 6 | 7 | public IDocsAPI ParentAPI 8 | { 9 | get; private set; 10 | } 11 | 12 | public string ArticleType => XmlHelper.GetAttributeValue(_xERelatedArticle, "type"); 13 | public string Href => XmlHelper.GetAttributeValue(_xERelatedArticle, "href"); 14 | public string Value => XmlHelper.GetNodesInPlainText(_xERelatedArticle); 15 | 16 | public DocsRelated(IDocsAPI parentAPI, XElement xeRelatedArticle) 17 | { 18 | ParentAPI = parentAPI; 19 | _xERelatedArticle = xeRelatedArticle; 20 | } 21 | 22 | public override string ToString() => Value; 23 | } -------------------------------------------------------------------------------- /XmlDocConflictResolver/Docs/DocsTypeParam.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | /// 4 | /// Each one of these typeparam objects live inside the Docs section inside the Member object. 5 | /// 6 | internal class DocsTypeParam 7 | { 8 | private readonly XElement _xEDocsTypeParam; 9 | public IDocsAPI ParentAPI 10 | { 11 | get; private set; 12 | } 13 | 14 | public string Name => XmlHelper.GetAttributeValue(_xEDocsTypeParam, "name"); 15 | 16 | public string Value => XmlHelper.GetNodesInPlainText(_xEDocsTypeParam); 17 | 18 | public DocsTypeParam(IDocsAPI parentAPI, XElement xeDocsTypeParam) 19 | { 20 | ParentAPI = parentAPI; 21 | _xEDocsTypeParam = xeDocsTypeParam; 22 | } 23 | } -------------------------------------------------------------------------------- /XmlDocConflictResolver/Docs/DocsTypeSignature.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | internal class DocsTypeSignature 4 | { 5 | private readonly XElement _xETypeSignature; 6 | 7 | public string Language => XmlHelper.GetAttributeValue(_xETypeSignature, "Language"); 8 | public string Value => XmlHelper.GetAttributeValue(_xETypeSignature, "Value"); 9 | 10 | public DocsTypeSignature(XElement xeTypeSignature) => _xETypeSignature = xeTypeSignature; 11 | } -------------------------------------------------------------------------------- /XmlDocConflictResolver/Docs/IDocsAPI.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | internal interface IDocsAPI 4 | { 5 | public abstract APIKind Kind { get; } 6 | public abstract bool InheritDoc { get; } 7 | public abstract bool Changed { get; set; } 8 | public abstract string FilePath { get; set; } 9 | public abstract string DocId { get; } 10 | public abstract string DocIdUnprefixed { get; } 11 | public abstract string InheritDocCref { get; } 12 | public abstract XElement Docs { get; } 13 | public abstract List Params { get; } 14 | public abstract List TypeParams { get; } 15 | public abstract string Summary { get; } 16 | public abstract string Returns { get; } 17 | public abstract string Remarks { get; } 18 | } -------------------------------------------------------------------------------- /XmlDocConflictResolver/IntelliSenseXml/IntelliSenseXmlException.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | internal class IntelliSenseXmlException 4 | { 5 | public XElement XEException 6 | { 7 | get; 8 | private set; 9 | } 10 | 11 | private string _cref = string.Empty; 12 | public string Cref 13 | { 14 | get 15 | { 16 | if (string.IsNullOrWhiteSpace(_cref)) 17 | { 18 | _cref = XmlHelper.GetAttributeValue(XEException, "cref"); 19 | } 20 | return _cref; 21 | } 22 | } 23 | 24 | private string _value = string.Empty; 25 | public string Value 26 | { 27 | get 28 | { 29 | if (string.IsNullOrWhiteSpace(_value)) 30 | { 31 | _value = XmlHelper.GetNodesInPlainText(XEException); 32 | } 33 | return _value; 34 | } 35 | set 36 | { 37 | _value = value; 38 | 39 | XEException.Value = value; 40 | } 41 | } 42 | 43 | public IntelliSenseXmlException(XElement xeException) => XEException = xeException; 44 | 45 | public override string ToString() => $"{Cref} - {Value}"; 46 | } 47 | -------------------------------------------------------------------------------- /XmlDocConflictResolver/IntelliSenseXml/IntelliSenseXmlFile.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using System.Xml.Linq; 3 | 4 | internal class IntelliSenseXmlFile 5 | { 6 | public IntelliSenseXmlFile(XDocument xDoc, string filePath, Encoding encoding) 7 | { 8 | Xdoc = xDoc; 9 | FilePath = filePath; 10 | FileEncoding = encoding; 11 | } 12 | 13 | public XDocument Xdoc { get; private set; } 14 | public string FilePath { get; private set; } 15 | public Encoding FileEncoding { get; private set; } 16 | public bool Changed { get; set; } = false; 17 | } 18 | -------------------------------------------------------------------------------- /XmlDocConflictResolver/IntelliSenseXml/IntelliSenseXmlParam.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | internal class IntelliSenseXmlParam 4 | { 5 | public XElement XEParam 6 | { 7 | get; 8 | private set; 9 | } 10 | 11 | private string _name = string.Empty; 12 | public string Name 13 | { 14 | get 15 | { 16 | if (string.IsNullOrWhiteSpace(_name)) 17 | { 18 | _name = XmlHelper.GetAttributeValue(XEParam, "name"); 19 | } 20 | return _name; 21 | } 22 | } 23 | 24 | private string _value = string.Empty; 25 | public string Value 26 | { 27 | get 28 | { 29 | if (string.IsNullOrWhiteSpace(_value)) 30 | { 31 | _value = XmlHelper.GetNodesInPlainText(XEParam); 32 | } 33 | return _value; 34 | } 35 | set 36 | { 37 | _value = value; 38 | 39 | // Update the XML model too. 40 | XEParam.Value = _value; 41 | } 42 | } 43 | 44 | public IntelliSenseXmlParam(XElement xeParam) => XEParam = xeParam; 45 | } 46 | -------------------------------------------------------------------------------- /XmlDocConflictResolver/IntelliSenseXml/IntelliSenseXmlTypeParam.cs: -------------------------------------------------------------------------------- 1 | using System.Xml.Linq; 2 | 3 | internal class IntelliSenseXmlTypeParam 4 | { 5 | public XElement XETypeParam; 6 | 7 | private string _name = string.Empty; 8 | public string Name 9 | { 10 | get 11 | { 12 | if (string.IsNullOrWhiteSpace(_name)) 13 | { 14 | _name = XmlHelper.GetAttributeValue(XETypeParam, "name"); 15 | } 16 | return _name; 17 | } 18 | } 19 | 20 | private string _value = string.Empty; 21 | public string Value 22 | { 23 | get 24 | { 25 | if (string.IsNullOrWhiteSpace(_value)) 26 | { 27 | _value = XmlHelper.GetNodesInPlainText(XETypeParam); 28 | } 29 | return _value; 30 | } 31 | set 32 | { 33 | _value = value; 34 | 35 | XETypeParam.Value = value; 36 | } 37 | } 38 | 39 | public IntelliSenseXmlTypeParam(XElement xeTypeParam) => XETypeParam = xeTypeParam; 40 | } -------------------------------------------------------------------------------- /XmlDocConflictResolver/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "XmlDocConflictResolver": { 4 | "commandName": "Project", 5 | "commandLineArgs": "--ixml \"C:\\Users\\gewarren\\Desktop\\Test Files\\Logging.Console\" --ecmaxml C:\\Users\\gewarren\\dotnet-api-docs\\xml > output.txt" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /XmlDocConflictResolver/XmlDocConflictResolver.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /actions/dependabot-bot/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /actions/dependabot-bot/action.yml: -------------------------------------------------------------------------------- 1 | name: '.NET dependabot bot' 2 | description: Automatically keep dependabot.yml files updated. 3 | author: 'David Pine' 4 | branding: 5 | icon: shield 6 | color: blue 7 | inputs: 8 | root-directory: 9 | description: 'The root directory in which to run the automated dependabot evaluation.' 10 | default: '/github/workspace' 11 | dependabot-yml-path: 12 | description: 'The system file path to the dependabot.yml file.' 13 | default: '.github/dependabot.yml' 14 | 15 | runs: 16 | using: docker 17 | image: ./src/dependabot-bot/Dockerfile 18 | args: 19 | - ${{ inputs.root-directory }} 20 | - ${{ inputs.dependabot-yml-path }} 21 | -------------------------------------------------------------------------------- /actions/dependabot-bot/src/dependabot-bot/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0 as build-env 2 | # Copy everything and publish the release (publish implicitly restores and builds) 3 | WORKDIR /app 4 | COPY . ./ 5 | RUN dotnet publish "dependabot-bot.csproj" -c Release -o out --no-self-contained 6 | 7 | # Relayer the .NET SDK, anew with the build output 8 | FROM mcr.microsoft.com/dotnet/sdk:9.0 9 | COPY --from=build-env /app/out . 10 | ENTRYPOINT [ "dotnet", "/dependabot-bot.dll" ] 11 | -------------------------------------------------------------------------------- /actions/dependabot-bot/src/dependabot-bot/Extensions/StringBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Dependabot.Bot.Extensions; 2 | 3 | internal static class StringBuilderExtensions 4 | { 5 | internal static void WriteLineToBufferAndOutput( 6 | this StringBuilder buffer, string content, bool isLimitReached) 7 | { 8 | if (isLimitReached) 9 | { 10 | WriteLine("LIMIT REACHED, OVERFLOW IS DISCARDED!"); 11 | WriteLine(content); 12 | } 13 | else 14 | { 15 | buffer.AppendLine(content); 16 | WriteLine(content); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /actions/dependabot-bot/src/dependabot-bot/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Dependabot.Bot.Extensions; 2 | 3 | global using System.Diagnostics.CodeAnalysis; 4 | global using System.Net.Http.Json; 5 | global using System.Text; 6 | global using System.Text.RegularExpressions; 7 | 8 | global using static System.Console; -------------------------------------------------------------------------------- /actions/dependabot-bot/src/dependabot-bot/Program.Services.cs: -------------------------------------------------------------------------------- 1 | using Pathological.ProjectSystem.Services; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | static partial class Program 5 | { 6 | static IDiscoveryService AddAndGetDiscoveryService() 7 | { 8 | var serviceProvider = new ServiceCollection() 9 | .AddDotNetProjectSystem() 10 | .BuildServiceProvider(); 11 | 12 | return serviceProvider.GetRequiredService(); 13 | } 14 | } -------------------------------------------------------------------------------- /actions/docs-verifier/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | insert_final_newline = true 6 | 7 | [*.{xml,csproj,props,targets}] 8 | indent_size = 2 9 | 10 | [*.cs] 11 | indent_size = 4 12 | tab_width = 4 13 | end_of_line = crlf 14 | 15 | dotnet_sort_system_directives_first = true 16 | 17 | # CA1801: Review unused parameters - already removed in NetAnalyzers 6 in favor of IDE0060 18 | dotnet_diagnostic.CA1801.severity = none 19 | 20 | # CA2007: Consider calling ConfigureAwait on the awaited task 21 | dotnet_diagnostic.CA2007.severity = none 22 | 23 | # IDE0044: Add readonly modifier 24 | dotnet_style_readonly_field = true 25 | 26 | # IDE0022: Use block body for methods 27 | dotnet_diagnostic.IDE0022.severity = silent 28 | csharp_style_expression_bodied_methods = when_on_single_line 29 | 30 | # IDE0021: Use block body for constructors 31 | dotnet_diagnostic.IDE0021.severity = silent 32 | csharp_style_expression_bodied_constructors = when_on_single_line 33 | 34 | # IDE0046: Convert to conditional expression 35 | dotnet_diagnostic.IDE0046.severity = silent 36 | 37 | # IDE0008: Use explicit type - Replaced with YAnalyzers. 38 | dotnet_diagnostic.IDE0008.severity = none 39 | 40 | # CA1014: Mark assemblies with CLSCompliant 41 | dotnet_diagnostic.CA1014.severity = none 42 | -------------------------------------------------------------------------------- /actions/docs-verifier/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | enable 6 | true 7 | latest-All 8 | true 9 | true 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /actions/docs-verifier/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build 2 | WORKDIR /app 3 | COPY . ./ 4 | RUN dotnet publish ./src/ActionRunner/ActionRunner.csproj -c Release -o out --no-self-contained 5 | 6 | # Build the runtime image 7 | FROM mcr.microsoft.com/dotnet/runtime:9.0 8 | COPY --from=build /app/out . 9 | 10 | ENTRYPOINT [ "dotnet", "/ActionRunner.dll" ] 11 | -------------------------------------------------------------------------------- /actions/docs-verifier/README.md: -------------------------------------------------------------------------------- 1 | # MSDocs Build Verifier 2 | 3 | A work-in-progress for a GitHub Action that does various checks for MS Docs repositories. This is based on [markdown-links-verifier](https://github.com/Youssef1313/markdown-links-verifier). 4 | -------------------------------------------------------------------------------- /actions/docs-verifier/action.yml: -------------------------------------------------------------------------------- 1 | name: MSDocs Build Verifier 2 | description: Various checks for MSDocs repositories 3 | 4 | runs: 5 | using: docker 6 | image: Dockerfile 7 | -------------------------------------------------------------------------------- /actions/docs-verifier/docs/json-config-file.md: -------------------------------------------------------------------------------- 1 | # Configuration file 2 | 3 | Starting with v0.0.8, a configuration file *markdown-links-verifier-config.json* support was added. 4 | 5 | ## `excludeStartingWith` 6 | 7 | Starting with v0.0.8, the configuration file can contain an `excludeStartingWith` array used to exclude links starting with given prefixes. 8 | 9 | ### Example 10 | 11 | Given the following *markdown-links-verifier-config.json* file in the repository root, it will disallow links starting with `xref:` or `~/` from being verified: 12 | 13 | ```json 14 | { 15 | "excludeStartingWith": [ 16 | "xref:", 17 | "~/", 18 | ] 19 | } 20 | ``` 21 | 22 | ### Rationale (use case) 23 | 24 | Some repositories may be using specific markdown extensions that shouldn't be flagged. For example, Microsoft Docs has "xref:" for API links. The workflow shouldn't attempt to analyze them. 25 | 26 | See [issue #63](https://github.com/Youssef1313/markdown-links-verifier/issues/63) for more information. -------------------------------------------------------------------------------- /actions/docs-verifier/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/ActionRunner/ActionRunner.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/BuildVerifier.IO.Abstractions/BaseMappedConfigurationReader.cs: -------------------------------------------------------------------------------- 1 | namespace BuildVerifier.IO.Abstractions; 2 | 3 | public abstract class BaseMappedConfigurationReader 4 | : BaseConfigurationReader 5 | where TConfigurationFile : class 6 | { 7 | /// 8 | /// Maps the into a consumer-defined . 9 | /// 10 | public abstract ValueTask MapConfigurationAsync(); 11 | } 12 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/BuildVerifier.IO.Abstractions/BuildVerifier.IO.Abstractions.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/GitHub/GitHub.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/GitHub/PullRequestFileExtensions.cs: -------------------------------------------------------------------------------- 1 | using Octokit; 2 | 3 | namespace GitHub; 4 | 5 | public static class PullRequestFileExtensions 6 | { 7 | // Didn't find documentation for these values :( 8 | private const string FILE_ADDED_STATUS = "added"; 9 | private const string FILE_RENAMED_STATUS = "renamed"; 10 | private const string FILE_REMOVED_STATUS = "removed"; 11 | 12 | /// 13 | /// An added file has a non-null and 14 | /// 15 | public static bool IsRenamed(this PullRequestFile file) => file?.Status == FILE_RENAMED_STATUS; 16 | 17 | /// 18 | /// An added file has a null 19 | /// 20 | public static bool IsAdded(this PullRequestFile file) => file?.Status == FILE_ADDED_STATUS; 21 | 22 | /// 23 | /// An added file has a null 24 | /// 25 | public static bool IsRemoved(this PullRequestFile file) => file?.Status == FILE_REMOVED_STATUS; 26 | } 27 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/MarkdownLinksVerifier/Configuration/ConfigurationReader.cs: -------------------------------------------------------------------------------- 1 | using BuildVerifier.IO.Abstractions; 2 | 3 | namespace MarkdownLinksVerifier.Configuration; 4 | 5 | public class ConfigurationReader : BaseConfigurationReader 6 | { 7 | public ConfigurationReader() 8 | { 9 | ConfigurationFileName = "markdown-links-verifier-config.json"; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/MarkdownLinksVerifier/Configuration/MarkdownLinksVerifierConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace MarkdownLinksVerifier.Configuration; 5 | 6 | public record MarkdownLinksVerifierConfiguration( 7 | [property: JsonPropertyName("excludeStartingWith")] ImmutableArray ExcludeStartingWith) 8 | { 9 | public bool IsLinkExcluded(string link) 10 | => !ExcludeStartingWith.IsDefaultOrEmpty 11 | && ExcludeStartingWith.Any(excludedPrefix => link.StartsWith(excludedPrefix, StringComparison.Ordinal)); 12 | } 13 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/MarkdownLinksVerifier/LinkClassifier/Classifier.cs: -------------------------------------------------------------------------------- 1 | namespace MarkdownLinksVerifier.LinkClassifier; 2 | 3 | internal static class Classifier 4 | { 5 | internal static LinkClassification Classify(string link) 6 | { 7 | if (Uri.TryCreate(link, UriKind.Absolute, out Uri? uri)) 8 | { 9 | return uri.Scheme switch 10 | { 11 | "http" => LinkClassification.Online, 12 | "https" => LinkClassification.Online, 13 | "ftp" => LinkClassification.Online, 14 | "mailto" => LinkClassification.Mailto, 15 | _ => LinkClassification.Local 16 | }; 17 | } 18 | 19 | return LinkClassification.Local; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/MarkdownLinksVerifier/LinkClassifier/LinkClassification.cs: -------------------------------------------------------------------------------- 1 | namespace MarkdownLinksVerifier.LinkClassifier; 2 | 3 | internal enum LinkClassification 4 | { 5 | /// 6 | /// Indicates an http/https link. 7 | /// 8 | Online, 9 | /// 10 | /// Indicates a link to a local file. 11 | /// 12 | Local, 13 | /// 14 | /// Indicates a mailto: link. 15 | /// 16 | Mailto, 17 | } 18 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/MarkdownLinksVerifier/LinkValidator/ILinkValidator.cs: -------------------------------------------------------------------------------- 1 | namespace MarkdownLinksVerifier.LinkValidator; 2 | 3 | internal interface ILinkValidator 4 | { 5 | ValidationResult Validate(string link, string filePath); 6 | } 7 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/MarkdownLinksVerifier/LinkValidator/MailtoLinkValidator.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.Diagnostics; 3 | 4 | namespace MarkdownLinksVerifier.LinkValidator; 5 | 6 | internal class MailtoLinkValidator : ILinkValidator 7 | { 8 | private static readonly EmailAddressAttribute emailAddressAttribute = new(); 9 | 10 | public ValidationResult Validate(string link, string filePath) 11 | { 12 | Debug.Assert(link.StartsWith("mailto:", StringComparison.OrdinalIgnoreCase)); 13 | return new ValidationResult { AbsolutePathWithoutHeading = link, State = emailAddressAttribute.IsValid(link["mailto:".Length..]) ? ValidationState.Valid : ValidationState.LinkNotFound }; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/MarkdownLinksVerifier/LinkValidator/OnlineLinkValidator.cs: -------------------------------------------------------------------------------- 1 | namespace MarkdownLinksVerifier.LinkValidator; 2 | 3 | // Singleton? 4 | internal class OnlineLinkValidator : ILinkValidator 5 | { 6 | public ValidationResult Validate(string link, string filePath) 7 | { 8 | // TODO: implement this. 9 | return new ValidationResult { State = ValidationState.Valid, AbsolutePathWithoutHeading = link }; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/MarkdownLinksVerifier/LinkValidator/ValidationResult.cs: -------------------------------------------------------------------------------- 1 | namespace MarkdownLinksVerifier; 2 | 3 | /// 4 | /// For a link on the form [Text](./path/to/file.md#heading-reference): 5 | /// 6 | /// If file.md is found and the heading reference is correct, result will be 7 | /// If file.md is found but the heading reference is invalid, result will be 8 | /// If file.md is not found, result will be 9 | /// 10 | /// 11 | internal enum ValidationState 12 | { 13 | Valid, 14 | LinkNotFound, 15 | HeadingNotFound, 16 | } 17 | 18 | internal struct ValidationResult 19 | { 20 | public ValidationState State; 21 | 22 | /// 23 | /// The expected absolute path of the linked file. 24 | /// 25 | public string AbsolutePathWithoutHeading; 26 | } 27 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/MarkdownLinksVerifier/MarkdownLinksVerifier.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/RedirectionVerifier/DocfxConfigurationReader.cs: -------------------------------------------------------------------------------- 1 | using BuildVerifier.IO.Abstractions; 2 | using Microsoft.Extensions.FileSystemGlobbing; 3 | 4 | namespace RedirectionVerifier; 5 | 6 | public class DocfxConfigurationReader 7 | : BaseMappedConfigurationReader> 8 | { 9 | private static readonly Matcher s_matchAllMatcher = new Matcher().AddInclude("**"); 10 | 11 | public DocfxConfigurationReader() 12 | { 13 | ConfigurationFileName = "docfx.json"; 14 | } 15 | 16 | public override async ValueTask> MapConfigurationAsync() 17 | { 18 | DocfxConfiguration? configuration = await ReadConfigurationAsync(); 19 | return AdjustMatchers(configuration?.GetMatchers()); 20 | } 21 | 22 | private static IEnumerable AdjustMatchers(IEnumerable? matchers) 23 | => (matchers is null || !matchers.Any()) 24 | ? new[] { s_matchAllMatcher } 25 | : matchers; 26 | } 27 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/RedirectionVerifier/NavigationOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace RedirectionVerifier; 4 | 5 | public record NavigationOptions( 6 | [property: JsonPropertyName("repoTocFolder")] string? RepoTocFolder, 7 | [property: JsonPropertyName("repoIndexFolder")] string? RepoIndexFolder) 8 | { 9 | /// 10 | /// The configured path for the "What's new" content. 11 | /// 12 | internal string? WhatsNewPath => RepoTocFolder ?? RepoIndexFolder; 13 | } 14 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/RedirectionVerifier/OpenPublishingConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace RedirectionVerifier; 5 | 6 | public sealed class OpenPublishingConfig 7 | { 8 | [JsonPropertyName("redirection_files")] 9 | public ImmutableArray? RedirectionFiles { get; set; } = null; 10 | } 11 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/RedirectionVerifier/OpenPublishingConfigReader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using BuildVerifier.IO.Abstractions; 3 | 4 | namespace RedirectionVerifier; 5 | 6 | public class OpenPublishingConfigReader 7 | : BaseMappedConfigurationReader?> 8 | { 9 | public OpenPublishingConfigReader() 10 | { 11 | ConfigurationFileName = ".openpublishing.publish.config.json"; 12 | } 13 | 14 | public override async ValueTask?> MapConfigurationAsync() 15 | { 16 | OpenPublishingConfig? configuration = await ReadConfigurationAsync(); 17 | if (configuration is { RedirectionFiles: { Length: > 0 } }) 18 | { 19 | return configuration.RedirectionFiles; 20 | } 21 | 22 | return default; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/RedirectionVerifier/OpenPublishingRedirectionReader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using BuildVerifier.IO.Abstractions; 3 | 4 | namespace RedirectionVerifier; 5 | 6 | public class OpenPublishingRedirectionReader 7 | : BaseMappedConfigurationReader> 8 | { 9 | public OpenPublishingRedirectionReader(string configFileName) 10 | { 11 | ConfigurationFileName = configFileName; 12 | } 13 | 14 | public override async ValueTask> MapConfigurationAsync() 15 | { 16 | OpenPublishingRedirections? configuration = await ReadConfigurationAsync(); 17 | if (configuration is { Redirections: { Length: > 0 } }) 18 | { 19 | return configuration.Redirections; 20 | } 21 | 22 | return default; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/RedirectionVerifier/OpenPublishingRedirections.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | using System.Text.Json.Serialization; 3 | 4 | namespace RedirectionVerifier; 5 | 6 | public sealed class OpenPublishingRedirections 7 | { 8 | [JsonPropertyName("redirections")] 9 | public ImmutableArray Redirections { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/RedirectionVerifier/Redirection.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace RedirectionVerifier; 4 | 5 | public sealed class Redirection 6 | { 7 | [JsonPropertyName("source_path")] 8 | public string? SourcePath { get; set; } = null; 9 | 10 | [JsonPropertyName("source_path_from_root")] 11 | public string? SourcePathFromRoot { get; set; } = null; 12 | 13 | [JsonPropertyName("redirect_url")] 14 | #pragma warning disable CA1056 // URI-like properties should not be strings → Could throw 15 | public string RedirectUrl { get; set; } = null!; 16 | #pragma warning restore CA1056 // URI-like properties should not be strings 17 | 18 | public bool MatchesSourcePath(string path) 19 | => SourcePath == path || SourcePathFromRoot == $"/{path}"; 20 | } 21 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/RedirectionVerifier/RedirectionHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Immutable; 2 | 3 | namespace RedirectionVerifier; 4 | 5 | public static class RedirectionHelpers 6 | { 7 | public static async Task?> GetRedirectionFilesAsync() 8 | { 9 | OpenPublishingConfigReader configReader = new(); 10 | return await configReader.MapConfigurationAsync(); 11 | } 12 | 13 | public static async Task> GetRedirectionFileNames() 14 | { 15 | ImmutableArray? redirectionFileNames = await GetRedirectionFilesAsync(); 16 | 17 | // If no redirection files are found in the OPS config, just use the default name. 18 | if (redirectionFileNames == null) 19 | redirectionFileNames = ImmutableArray.Create(".openpublishing.redirection.json"); 20 | 21 | Console.WriteLine($"The following {redirectionFileNames.Value.Length} redirection files are registered:"); 22 | foreach (string filename in redirectionFileNames) 23 | { 24 | Console.WriteLine(filename); 25 | } 26 | 27 | return redirectionFileNames.Value; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/RedirectionVerifier/RedirectionVerifier.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/RedirectionVerifier/WhatsNewConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json.Serialization; 2 | 3 | namespace RedirectionVerifier; 4 | 5 | /// 6 | /// Schema: https://whatsnewapi.azurewebsites.net/schema 7 | /// Omitted parts of this that are not relevant to our needs. 8 | /// 9 | public record WhatsNewConfiguration( 10 | [property: JsonPropertyName("docSetProductName")] string DocSetProductName, 11 | [property: JsonPropertyName("navigationOptions")] NavigationOptions? NavigationOptions); 12 | -------------------------------------------------------------------------------- /actions/docs-verifier/src/RedirectionVerifier/WhatsNewConfigurationReader.cs: -------------------------------------------------------------------------------- 1 | using BuildVerifier.IO.Abstractions; 2 | 3 | namespace RedirectionVerifier; 4 | 5 | public class WhatsNewConfigurationReader 6 | : BaseMappedConfigurationReader 7 | { 8 | public WhatsNewConfigurationReader() 9 | { 10 | ConfigurationFileName = ".whatsnew.json"; 11 | } 12 | 13 | public override async ValueTask MapConfigurationAsync() 14 | { 15 | WhatsNewConfiguration? configuration = await ReadConfigurationAsync(); 16 | if (configuration?.NavigationOptions is not null) 17 | { 18 | return configuration.NavigationOptions.WhatsNewPath; 19 | } 20 | 21 | return default; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /actions/docs-verifier/tests/GitHub.UnitTests/GitHub.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /actions/docs-verifier/tests/MarkdownLinksVerifier/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | 6 | using System.Diagnostics.CodeAnalysis; 7 | 8 | [assembly: SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Underscores are okay for unit tests")] 9 | [assembly: SuppressMessage("Style", "IDE0022:Use expression body for methods", Justification = "Noisy for test code")] 10 | -------------------------------------------------------------------------------- /actions/docs-verifier/tests/MarkdownLinksVerifier/LinkValidatorTests/MailtoLinkValidatorTests.cs: -------------------------------------------------------------------------------- 1 | using MarkdownLinksVerifier.LinkValidator; 2 | using Xunit; 3 | 4 | namespace MarkdownLinksVerifier.UnitTests.LinkValidatorTests; 5 | 6 | public class MailtoLinkValidatorTests 7 | { 8 | [Fact] 9 | public void TestEmptyMailto() 10 | { 11 | Assert.Equal(ValidationState.LinkNotFound, new MailtoLinkValidator().Validate("mailto:", "UNUSED").State); 12 | } 13 | 14 | [Fact] 15 | public void TestInvalidEmail() 16 | { 17 | Assert.Equal(ValidationState.LinkNotFound, new MailtoLinkValidator().Validate("mailto:person", "UNUSED").State); 18 | } 19 | 20 | [Fact] 21 | public void TestValidEmail() 22 | { 23 | Assert.Equal(ValidationState.Valid, new MailtoLinkValidator().Validate("mailto:person@company.com", "UNUSED").State); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /actions/docs-verifier/tests/MarkdownLinksVerifier/LinkValidatorTests/Utilities/FilesCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace MarkdownLinksVerifier.UnitTests.LinkValidatorTests; 4 | 5 | internal sealed class FilesCollection : IEnumerable> 6 | { 7 | private readonly Dictionary _files = new(); 8 | 9 | public void Add(string path, string contents) 10 | => _files.Add(path.Replace('\\', Path.DirectorySeparatorChar).Replace('/', Path.DirectorySeparatorChar), contents); 11 | 12 | public IEnumerator> GetEnumerator() => _files.GetEnumerator(); 13 | 14 | IEnumerator IEnumerable.GetEnumerator() => _files.GetEnumerator(); 15 | } 16 | -------------------------------------------------------------------------------- /actions/docs-verifier/tests/MarkdownLinksVerifier/MarkdownLinksVerifier.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | all 17 | 18 | 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | all 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /actions/docs-verifier/valid-test-cases/MSDocsSpecific/Includes/aspnetcore.md: -------------------------------------------------------------------------------- 1 | The following breaking changes in ASP.NET Core 3.0 and 3.1 are documented on this page: 2 | - [Obsolete Antiforgery, CORS, Diagnostics, MVC, and Routing APIs removed](#obsolete-antiforgery-cors-diagnostics-mvc-and-routing-apis-removed) 3 | 4 | 5 | [!INCLUDE[Obsolete Antiforgery, CORS, Diagnostics, MVC, and Routing APIs removed](~/actions/docs-verifier/valid-test-cases/MSDocsSpecific/Includes/include.md)] 6 | -------------------------------------------------------------------------------- /actions/docs-verifier/valid-test-cases/MSDocsSpecific/Includes/include.md: -------------------------------------------------------------------------------- 1 | ### Obsolete Antiforgery, CORS, Diagnostics, MVC, and Routing APIs removed 2 | 3 | Obsolete members and compatibility switches in ASP.NET Core 2.2 were removed. 4 | -------------------------------------------------------------------------------- /actions/docs-verifier/valid-test-cases/MSDocsSpecific/Includes2/core/compatibility/2.1.md: -------------------------------------------------------------------------------- 1 | ## MSBuild 2 | - [Project tools now included in SDK](#project-tools-now-included-in-sdk) 3 | [!INCLUDE [DotNetCliToolReference project elements removed for bundled tools](../../includes/dotnetclitoolreference.md)] 4 | -------------------------------------------------------------------------------- /actions/docs-verifier/valid-test-cases/MSDocsSpecific/Includes2/core/tools/sdk-errors/netsdk1059.md: -------------------------------------------------------------------------------- 1 | For more information, see [Project tools now included in SDK](../../compatibility/2.1.md#project-tools-now-included-in-sdk). -------------------------------------------------------------------------------- /actions/docs-verifier/valid-test-cases/MSDocsSpecific/Includes2/includes/dotnetclitoolreference.md: -------------------------------------------------------------------------------- 1 | ### Project tools now included in SDK 2 | 3 | The .NET Core 2.1 SDK now includes common CLI tooling, and you no longer need to reference these tools from the project. 4 | -------------------------------------------------------------------------------- /actions/docs-verifier/valid-test-cases/MarkdownLinksVerifier/test-query-parameters/File.md: -------------------------------------------------------------------------------- 1 | ![alt text](image.png) 2 | [text](image.png) 3 | ![alt text](image.png?raw=true) 4 | [text](image.png?raw=true) 5 | 6 | ![alt text](./image.png) 7 | [text](./image.png) 8 | ![alt text](./image.png?raw=true) 9 | [text](./image.png?raw=true) 10 | -------------------------------------------------------------------------------- /actions/docs-verifier/valid-test-cases/MarkdownLinksVerifier/test-query-parameters/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/docs-tools/e88a4c229f2fc2dbe5cfa3ffabbcef8489ffba50/actions/docs-verifier/valid-test-cases/MarkdownLinksVerifier/test-query-parameters/image.png -------------------------------------------------------------------------------- /actions/docs-verifier/valid-test-cases/MarkdownLinksVerifier/test1/File1.md: -------------------------------------------------------------------------------- 1 | [text](File1.md) 2 | [text](./File1.md) 3 | [text](/actions/docs-verifier/valid-test-cases/MarkdownLinksVerifier/test1/File1.md) 4 | [text](folder/Name%20With%20Space.md) 5 | [text](folder) 6 | [text](./folder) 7 | [text]() 8 | -------------------------------------------------------------------------------- /actions/docs-verifier/valid-test-cases/MarkdownLinksVerifier/test1/folder/Name With Space.md: -------------------------------------------------------------------------------- 1 | [text](../File1.md) 2 | [text](.././File1.md) 3 | -------------------------------------------------------------------------------- /actions/docs-verifier/valid-test-cases/README.md: -------------------------------------------------------------------------------- 1 | # Test cases 2 | 3 | This folder holds actual test cases that the tool will run *directly* against through the dogfooding workflow. 4 | -------------------------------------------------------------------------------- /actions/sequester/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /actions/sequester/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /actions/sequester/ImportIssues/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Quest2GitHub; 2 | global using Quest2GitHub.Options; 3 | -------------------------------------------------------------------------------- /actions/sequester/Quest2GitHub.Tests/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.Extensions.Configuration; 2 | global using Microsoft.Extensions.DependencyInjection; 3 | global using Microsoft.Extensions.Options; 4 | global using Quest2GitHub.Extensions; 5 | global using Quest2GitHub.Options; 6 | global using Xunit; 7 | -------------------------------------------------------------------------------- /actions/sequester/Quest2GitHub.Tests/QuestWorkItemTests.cs: -------------------------------------------------------------------------------- 1 | using Quest2GitHub.Models; 2 | 3 | namespace Quest2GitHub.Tests; 4 | 5 | public class QuestWorkItemTests 6 | { 7 | [Theory] 8 | [InlineData("short title")] 9 | [InlineData("A really long title, in fact, it's so long that we know it will exceed the max length of 255 characters imposed by the Azure DevOps API, thus proving our point, and being truncated in the object's .ctor. Isn't programming fun?! Wow, this title is really long...I hope we're done typing soon.")] 10 | public void QuestItemConstructorEnsuresTitleIsTruncated(string title) 11 | { 12 | var sut = new QuestWorkItem 13 | { 14 | Id = 777, 15 | ParentWorkItemId = 100, 16 | ParentRelationIndex = 1, 17 | Title = title, // Truncated on init 18 | State = "Wisconsin 🧀", 19 | Description = "Test description", 20 | AreaPath = "Test/Area", 21 | IterationPath = "Test/Path", 22 | AssignedToId = Guid.NewGuid(), 23 | StoryPoints = 1, 24 | Priority = 1, 25 | Tags = [] 26 | }; 27 | 28 | Assert.True(sut.Title.Length < 256); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /actions/sequester/Quest2GitHub.Tests/quest-import.json: -------------------------------------------------------------------------------- 1 | { 2 | "ImportOptions": { 3 | "GitHubOrg": "org", 4 | "GitHubRepo": "repo", 5 | "AzureDevOps": { 6 | "Org": "org", 7 | "Project": "proj", 8 | "AreaPath": "path" 9 | }, 10 | "ApiKeys": { 11 | "GitHubToken": "ght", 12 | "OSPOKey": "okey", 13 | "QuestKey": "qkey" 14 | }, 15 | "ImportTriggerLabel": "trigger-import", 16 | "ImportedLabel": "imported", 17 | "ParentNodes": [ 18 | { 19 | "Label": "okr-health", 20 | "ParentNodeId": 199082 21 | }, 22 | { 23 | "Label": "dotnet-csharp/svc", 24 | "ParentNodeId": 227484 25 | } 26 | ], 27 | "DefaultParentNode": 228485 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /actions/sequester/Quest2GitHub/Extensions/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Quest2GitHub.Extensions; 2 | 3 | public static class ServiceCollectionExtensions 4 | { 5 | public static IServiceCollection AddImportServices( 6 | this IServiceCollection services, IConfiguration importOptionsSection) 7 | { 8 | services.Configure(importOptionsSection); 9 | 10 | return services; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /actions/sequester/Quest2GitHub/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using DotNetDocs.Tools.GitHubCommunications; 2 | global using DotNetDocs.Tools.GraphQLQueries; 3 | global using Microsoft.DotnetOrg.Ospo; 4 | global using Microsoft.Extensions.Configuration; 5 | global using Microsoft.Extensions.DependencyInjection; 6 | global using Quest2GitHub.AzureDevOpsCommunications; 7 | global using Quest2GitHub.Extensions; 8 | global using Quest2GitHub.Models; 9 | global using Quest2GitHub.Options; 10 | global using System.Net.Http.Headers; 11 | global using System.Net.Mime; 12 | global using System.Text; 13 | global using System.Text.Json; 14 | global using System.Text.Json.Serialization; -------------------------------------------------------------------------------- /actions/sequester/Quest2GitHub/Models/QuestIteration.cs: -------------------------------------------------------------------------------- 1 | namespace Quest2GitHub.Models; 2 | 3 | public class QuestIteration 4 | { 5 | public required int Id { get; init; } 6 | public required Guid Identifier { get; init; } 7 | public required string Name { get; init; } 8 | public required string Path { get; init; } 9 | 10 | public bool IsInSemester(string semesterName) => Path.Contains(semesterName); 11 | 12 | public static QuestIteration CurrentIteration(IEnumerable iterations) 13 | { 14 | var currentYear = int.Parse(DateTime.Now.ToString("yyyy")); 15 | var currentMonth = DateTime.Now.ToString("MMM"); 16 | var iteration = IssueExtensions.ProjectIteration(currentMonth, currentYear, iterations); 17 | return iteration ?? throw new InvalidOperationException("No current iteration found."); 18 | } 19 | 20 | public static QuestIteration FutureIteration(IEnumerable iterations) 21 | => iterations.Single(sprint => sprint.Name is "Future"); 22 | 23 | override public string ToString() => $"{Identifier} {Id} {Name} ({Path})"; 24 | 25 | } 26 | -------------------------------------------------------------------------------- /actions/sequester/Quest2GitHub/Options/LocalFileReader.cs: -------------------------------------------------------------------------------- 1 | namespace Quest2GitHub.Options; 2 | 3 | public sealed class LocalFileReader 4 | { 5 | public async Task ReadOptionsAsync(string path) 6 | { 7 | try 8 | { 9 | var json = await File.ReadAllTextAsync(path); 10 | var options = JsonSerializer.Deserialize(json); 11 | 12 | options.WriteValuesToConsole(); 13 | if (options is not null) 14 | { 15 | options = options with 16 | { 17 | ApiKeys = EnvironmentVariableReader.GetApiKeys() 18 | }; 19 | } 20 | 21 | return options; 22 | } 23 | catch (Exception ex) 24 | { 25 | Console.Error.WriteLine($"Attempted reading: {path}, {ex}"); 26 | } 27 | 28 | return null; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /actions/sequester/Quest2GitHub/Quest2GitHub.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | 2.1.0.0 8 | 2.1.0.0 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /actions/sequester/action.yml: -------------------------------------------------------------------------------- 1 | name: Quest synchronizer 2 | description: Automatically synchronize GitHub issues with Quest (Azure DevOps). 3 | author: 'Bill Wagner' 4 | branding: 5 | icon: refresh-cw 6 | color: purple 7 | inputs: 8 | org: 9 | description: 'The organization the repo belongs to. Assign from github.repository_owner. Example, "dotnet".' 10 | default: 'dotnet' 11 | repo: 12 | description: 'The repository name. Example, "docs".' 13 | default: 'docs' 14 | issue: 15 | description: 'An optional issue number to target when being triggered for a single issue.' 16 | branch: 17 | description: 'The branch to target. Assign from github.ref_name. Example, "main".' 18 | default: 'main' 19 | duration: 20 | description: 'How many days updates to process. Issues must have been updated in that many recent days for processing.' 21 | default: '5' 22 | 23 | runs: 24 | using: docker 25 | image: ../../sequester.Dockerfile 26 | args: 27 | - '--org' 28 | - ${{ inputs.org }} 29 | - '--repo' 30 | - ${{ inputs.repo }} 31 | - '--issue' 32 | - ${{ inputs.issue }} 33 | - '--branch' 34 | - ${{ inputs.branch }} 35 | - '--duration' 36 | - ${{ inputs.duration }} 37 | -------------------------------------------------------------------------------- /actions/status-checker/.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ 4 | jest.config.js 5 | -------------------------------------------------------------------------------- /actions/status-checker/.gitattributes: -------------------------------------------------------------------------------- 1 | dist/** -diff linguist-generated=true -------------------------------------------------------------------------------- /actions/status-checker/.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | node_modules/ -------------------------------------------------------------------------------- /actions/status-checker/__tests__/3/three.md: -------------------------------------------------------------------------------- 1 | # THREE 2 | -------------------------------------------------------------------------------- /actions/status-checker/__tests__/file-heading-extractor.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "@jest/globals"; 2 | import { getHeadingTextFrom } from "../src/file-heading-extractor"; 3 | 4 | beforeAll(() => { 5 | process.env["GITHUB_REPOSITORY"] = "dotnet/docs"; 6 | }); 7 | 8 | describe("file-heading-extractor", () => { 9 | it("when calling getHeadingTextFrom correctly returns H1 value.", async () => { 10 | const path = "__tests__/sample.md"; 11 | const actual = await getHeadingTextFrom(path); 12 | expect(actual).toBe("The heading `System.Console` class"); 13 | }); 14 | 15 | it("when calling getHeadingTextFrom correctly returns title value.", async () => { 16 | const path = "__tests__/no-heading.md"; 17 | const actual = await getHeadingTextFrom(path); 18 | expect(actual).toBe("Phew, that worked!"); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /actions/status-checker/__tests__/main.test.ts: -------------------------------------------------------------------------------- 1 | import { wait } from "../src/wait"; 2 | import { describe, expect, it } from "@jest/globals"; 3 | 4 | describe("status-checker", () => { 5 | it("throws invalid number when given 'foo' string", async () => { 6 | const input = parseInt("foo", 10); 7 | await expect(wait(input)).rejects.toThrow("milliseconds not a number"); 8 | }); 9 | 10 | it("call to 'wait' actually waits 500 ms", async () => { 11 | const start = new Date(); 12 | await wait(500); 13 | const end = new Date(); 14 | var delta = Math.abs(end.getTime() - start.getTime()); 15 | expect(delta).toBeGreaterThan(450); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /actions/status-checker/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | clearMocks: true, 3 | moduleFileExtensions: ['js', 'ts'], 4 | testEnvironment: 'node', 5 | testMatch: ['**/*.test.ts'], 6 | testRunner: 'jest-circus/runner', 7 | transform: { 8 | '^.+\\.ts$': 'ts-jest' 9 | }, 10 | verbose: true 11 | } -------------------------------------------------------------------------------- /actions/status-checker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-action", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "TypeScript template action", 6 | "main": "lib/main.js", 7 | "scripts": { 8 | "build": "tsc", 9 | "format": "prettier --write **/*.ts", 10 | "format-check": "prettier --check **/*.ts", 11 | "package": "ncc build --source-map --license licenses.txt", 12 | "test": "jest --detectOpenHandles", 13 | "all": "npm run build && npm run format && npm run package && npm test" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/actions/typescript-action.git" 18 | }, 19 | "keywords": [ 20 | "actions", 21 | "node", 22 | "setup" 23 | ], 24 | "author": "", 25 | "license": "MIT", 26 | "dependencies": { 27 | "@actions/core": "^1.10.0", 28 | "@actions/github": "^6.0.0" 29 | }, 30 | "devDependencies": { 31 | "@types/jest": "^29.2.6", 32 | "@types/node": "^18.11.18", 33 | "@vercel/ncc": "^0.36.0", 34 | "jest": "^29.3.1", 35 | "jest-circus": "^29.3.1", 36 | "js-yaml": "^4.1.0", 37 | "prettier": "^2.8.3", 38 | "ts-jest": "^29.0.5", 39 | "typescript": "^4.9.4" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /actions/status-checker/src/main.ts: -------------------------------------------------------------------------------- 1 | import { wait } from "./wait"; 2 | import { isSuccessStatus } from "./status-checker"; 3 | import { setFailed } from "@actions/core"; 4 | import { tryUpdatePullRequestBody } from "./pull-updater"; 5 | import { workflowInput } from "./types/WorkflowInput"; 6 | 7 | async function run(): Promise { 8 | try { 9 | const token: string = workflowInput.repoToken; 10 | 11 | // Wait 60 seconds before checking status check result. 12 | await wait(60000); 13 | console.log("Waited 60 seconds."); 14 | 15 | // When the status is passed, try to update the PR body. 16 | const isSuccess = await isSuccessStatus(token); 17 | if (isSuccess) { 18 | console.log("✅ Build status is good..."); 19 | } else { 20 | console.log("❌ Build status has warnings or errors!"); 21 | } 22 | if (workflowInput.mode === "preview") { 23 | await tryUpdatePullRequestBody(token); 24 | } 25 | } catch (error: unknown) { 26 | const e = error as Error; 27 | setFailed(e.message); 28 | } 29 | } 30 | 31 | run(); 32 | -------------------------------------------------------------------------------- /actions/status-checker/src/types/ChangeType.ts: -------------------------------------------------------------------------------- 1 | export type ChangeType = 2 | | "ADDED" 3 | | "CHANGED" 4 | | "COPIED" 5 | | "DELETED" 6 | | "MODIFIED" 7 | | "RENAMED"; 8 | -------------------------------------------------------------------------------- /actions/status-checker/src/types/FileChange.ts: -------------------------------------------------------------------------------- 1 | import { ChangeType } from "./ChangeType"; 2 | 3 | export type FileChange = { 4 | readonly additions: number; 5 | readonly changeType: ChangeType; 6 | readonly deletions: number; 7 | readonly path: string; 8 | }; 9 | -------------------------------------------------------------------------------- /actions/status-checker/src/types/Mode.ts: -------------------------------------------------------------------------------- 1 | export type Mode = "preview" | "warning"; 2 | -------------------------------------------------------------------------------- /actions/status-checker/src/types/NodeOf.ts: -------------------------------------------------------------------------------- 1 | export type NodeOf = { 2 | readonly node: T; 3 | }; 4 | -------------------------------------------------------------------------------- /actions/status-checker/src/types/PageInfo.ts: -------------------------------------------------------------------------------- 1 | export type PageInfo = { 2 | hasNextPage: boolean; 3 | endCursor: string; 4 | }; 5 | -------------------------------------------------------------------------------- /actions/status-checker/src/types/Pull.ts: -------------------------------------------------------------------------------- 1 | import { FileChange } from "./FileChange"; 2 | import { NodeOf } from "./NodeOf"; 3 | import { PageInfo } from "./PageInfo"; 4 | import { PullRequestState } from "./PullRequestState"; 5 | 6 | export type Pull = { 7 | readonly body: string; 8 | readonly checksUrl: string; 9 | readonly changedFiles: number; 10 | readonly state: PullRequestState; 11 | readonly files: { 12 | readonly pageInfo: PageInfo; 13 | readonly edges: NodeOf[]; 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /actions/status-checker/src/types/PullRequestDetails.ts: -------------------------------------------------------------------------------- 1 | import { Pull } from "./Pull"; 2 | 3 | export type PullRequestDetails = { 4 | readonly repository: { 5 | readonly pullRequest: Pull; 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /actions/status-checker/src/types/PullRequestState.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * See https://docs.github.com/graphql/reference/enums#pullrequeststate 3 | */ 4 | export type PullRequestState = "CLOSED" | "MERGED" | "OPEN"; 5 | -------------------------------------------------------------------------------- /actions/status-checker/src/wait.ts: -------------------------------------------------------------------------------- 1 | export async function wait(milliseconds: number): Promise { 2 | return new Promise((resolve) => { 3 | if (isNaN(milliseconds)) { 4 | throw new Error("milliseconds not a number"); 5 | } 6 | 7 | setTimeout(() => resolve("done!"), milliseconds); 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /actions/status-checker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 4 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 5 | "outDir": "./lib", /* Redirect output structure to the directory. */ 6 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 7 | "strict": true, /* Enable all strict type-checking options. */ 8 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 9 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 10 | }, 11 | "exclude": ["node_modules", "**/*.test.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /cleanrepo.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0 as build-env 2 | # Copy everything and publish the release (publish implicitly restores and builds) 3 | WORKDIR /app 4 | COPY . ./ 5 | RUN dotnet publish "./cleanrepo/CleanRepo.csproj" -c Release -o out --no-self-contained 6 | 7 | # Relayer the .NET SDK, anew with the build output 8 | FROM mcr.microsoft.com/dotnet/sdk:9.0 9 | COPY --from=build-env /app/out . 10 | ENTRYPOINT [ "dotnet", "/CleanRepo.dll" ] 11 | # RUN chmod +x /multiplexer.sh 12 | # ENTRYPOINT [ "/bin/bash", "/multiplexer.sh" ] 13 | -------------------------------------------------------------------------------- /cleanrepo/CleanRepo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | enable 6 | enable 7 | Linux 8 | 9 | 10 | 11 | 12 | 13 | 14 | Always 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | PreserveNewest 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /cleanrepo/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 |  2 | // This file is used by Code Analysis to maintain SuppressMessage 3 | // attributes that are applied to this project. 4 | // Project-level suppressions either have no target or are given 5 | // a specific target and scoped to a namespace, type, member, etc. 6 | 7 | using System.Diagnostics.CodeAnalysis; 8 | 9 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "", Scope = "namespace", Target = "CleanRepo")] 10 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1304:Specify CultureInfo", Justification = "", Scope = "namespace", Target = "CleanRepo")] 11 | [assembly: SuppressMessage("Globalization", "CA1307:Specify StringComparison", Justification = "", Scope = "member", Target = "~M:CleanRepo.DocFxRepo.ProcessImagePath(System.String,System.IO.FileInfo)")] 12 | -------------------------------------------------------------------------------- /cleanrepo/Options.cs: -------------------------------------------------------------------------------- 1 | namespace CleanRepo; 2 | 3 | class Options 4 | { 5 | public string? DocFxDirectory { get; set; } 6 | public string? TargetDirectory { get; set; } 7 | public string? UrlBasePath { get; set; } 8 | public bool Delete { get; set; } = true; 9 | public bool XmlSource { get; set; } = false; 10 | public string? Function { get; set; } 11 | public string? OcrModelDirectory { get; set; } 12 | public string? FilterTextJsonFile { get; set; } 13 | public List? LimitReferencingDirectories { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /cleanrepo/Redirect.cs: -------------------------------------------------------------------------------- 1 | namespace CleanRepo; 2 | 3 | internal class Redirect 4 | { 5 | public string? source_path { get; set; } = null; 6 | public string? source_path_from_root { get; set; } = null; 7 | public string? source_path_absolute { get; set; } = null; 8 | public string? redirect_url { get; set; } 9 | public bool? redirect_document_id { get; set; } = null; 10 | } 11 | -------------------------------------------------------------------------------- /cleanrepo/RedirectionFile.cs: -------------------------------------------------------------------------------- 1 | namespace CleanRepo; 2 | 3 | internal class RedirectionFile 4 | { 5 | public IList? redirections { get; set; } 6 | } 7 | -------------------------------------------------------------------------------- /cleanrepo/appSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Options": { 3 | "DocFxDirectory": null, 4 | "TargetDirectory": null, 5 | "UrlBasePath": "/dotnet", 6 | "Function": "FindOrphanedArticles", 7 | "OcrModelDirectory": null, 8 | "FilterTextJsonFile": null, 9 | "Delete": true, 10 | "XmlSource": false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /quest-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "AzureDevOps": { 3 | "Org": "msft-skilling", 4 | "Project": "Content", 5 | "AreaPath": "Production\\Core AI\\DotNet and more\\dotnet" 6 | }, 7 | "ImportTriggerLabel": ":world_map: reQUEST", 8 | "ImportedLabel": ":pushpin: seQUESTered", 9 | "ParentNodes": [ 10 | { 11 | "Semester": "Selenium", 12 | "ParentNodeId": 286035 13 | }, 14 | { 15 | "Semester": "Bromine", 16 | "ParentNodeId": 405108 17 | } 18 | ], 19 | "DefaultParentNode": 405108 20 | } -------------------------------------------------------------------------------- /sequester.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0 as build-env 2 | # Copy everything and publish the release (publish implicitly restores and builds) 3 | WORKDIR /app 4 | COPY . ./ 5 | RUN dotnet publish "actions/sequester/ImportIssues/ImportIssues.csproj" -c Release -o out --no-self-contained 6 | 7 | # Relayer the .NET SDK, anew with the build output 8 | FROM mcr.microsoft.com/dotnet/sdk:9.0 9 | COPY --from=build-env /app/out . 10 | ENTRYPOINT [ "dotnet", "/ImportIssues.dll" ] 11 | -------------------------------------------------------------------------------- /smalltest.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0 as build-env 2 | # Copy everything and publish the release (publish implicitly restores and builds) 3 | WORKDIR /app 4 | COPY . ./ 5 | RUN dotnet publish "SmallRepo/SmallRepo.csproj" -c Release -o out --no-self-contained 6 | 7 | # Relayer the .NET SDK, anew with the build output 8 | FROM mcr.microsoft.com/dotnet/sdk:9.0 9 | COPY --from=build-env /app/out . 10 | ENTRYPOINT [ "dotnet", "/SmallRepo.dll" ] 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations.Generators/PullRequestSimulations.Generators.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | false 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | $(GetTargetPathDependsOn);GetDependencyTargetPaths 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.VisualStudio.TestTools.UnitTesting; -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/lots-o-projects/extensions/linq.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | true 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/lots-o-projects/partition_not_in_sln/Program.cs: -------------------------------------------------------------------------------- 1 | int chunkNumber = 1; 2 | foreach (int[] chunk in Enumerable.Range(0, 8).Chunk(3)) 3 | { 4 | Console.WriteLine($"Chunk {chunkNumber++}:"); 5 | foreach (int item in chunk) 6 | { 7 | Console.WriteLine($" {item}"); 8 | } 9 | 10 | Console.WriteLine(); 11 | } 12 | // This code produces the following output: 13 | // Chunk 1: 14 | // 0 15 | // 1 16 | // 2 17 | // 18 | //Chunk 2: 19 | // 3 20 | // 4 21 | // 5 22 | // 23 | //Chunk 3: 24 | // 6 25 | // 7 26 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/lots-o-projects/partition_not_in_sln/partition.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | true 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/patternmatching/childfolder/other.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/patternmatching/patternmatching.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/samefolder/project1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/samefolder/project2.vbproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/sln_no_proj/some_code/Planet.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | record Planet( 4 | string Name, 5 | PlanetType Type, 6 | int OrderFromSun) 7 | { 8 | public static readonly Planet Mercury = 9 | new(nameof(Mercury), PlanetType.Rock, 1); 10 | 11 | public static readonly Planet Venus = 12 | new(nameof(Venus), PlanetType.Rock, 2); 13 | 14 | public static readonly Planet Earth = 15 | new(nameof(Earth), PlanetType.Rock, 3); 16 | 17 | public static readonly Planet Mars = 18 | new(nameof(Mars), PlanetType.Rock, 4); 19 | 20 | public static readonly Planet Jupiter = 21 | new(nameof(Jupiter), PlanetType.Gas, 5); 22 | 23 | public static readonly Planet Saturn = 24 | new(nameof(Saturn), PlanetType.Gas, 6); 25 | 26 | public static readonly Planet Uranus = 27 | new(nameof(Uranus), PlanetType.Liquid, 7); 28 | 29 | public static readonly Planet Neptune = 30 | new(nameof(Neptune), PlanetType.Liquid, 8); 31 | 32 | // Yes, I know... not technically a planet anymore 33 | public static readonly Planet Pluto = 34 | new(nameof(Pluto), PlanetType.Ice, 9); 35 | } 36 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/sln_no_proj/some_code/PlanetType.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | enum PlanetType 4 | { 5 | Rock, 6 | Ice, 7 | Gas, 8 | Liquid 9 | }; 10 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/sln_no_proj/some_code/Program.DistinctBy.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | public static partial class Program 4 | { 5 | internal static void DistinctByExample() 6 | { 7 | Console.WriteLine("DistinctBy:"); 8 | 9 | // 10 | Planet[] planets = 11 | { 12 | Planet.Mercury, 13 | Planet.Venus, 14 | Planet.Earth, 15 | Planet.Mars, 16 | Planet.Jupiter, 17 | Planet.Saturn, 18 | Planet.Uranus, 19 | Planet.Neptune, 20 | Planet.Pluto 21 | }; 22 | // 23 | 24 | // 25 | foreach (Planet planet in planets.DistinctBy(p => p.Type)) 26 | { 27 | Console.WriteLine(planet); 28 | } 29 | 30 | // This code produces the following output: 31 | // Planet { Name = Mercury, Type = Rock, OrderFromSun = 1 } 32 | // Planet { Name = Jupiter, Type = Gas, OrderFromSun = 5 } 33 | // Planet { Name = Uranus, Type = Liquid, OrderFromSun = 7 } 34 | // Planet { Name = Pluto, Type = Ice, OrderFromSun = 9 } 35 | // 36 | 37 | Console.WriteLine(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/sln_no_proj/some_code/Program.ExceptBy.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | public static partial class Program 4 | { 5 | internal static void ExceptByExample() 6 | { 7 | Console.WriteLine("ExceptBy:"); 8 | 9 | // 10 | Planet[] planets = 11 | { 12 | Planet.Mercury, 13 | Planet.Venus, 14 | Planet.Earth, 15 | Planet.Jupiter 16 | }; 17 | 18 | Planet[] morePlanets = 19 | { 20 | Planet.Mercury, 21 | Planet.Earth, 22 | Planet.Mars, 23 | Planet.Jupiter 24 | }; 25 | // 26 | 27 | // 28 | // A shared "keySelector" 29 | static string PlanetNameSelector(Planet planet) => planet.Name; 30 | 31 | foreach (Planet planet in 32 | planets.ExceptBy( 33 | morePlanets.Select(PlanetNameSelector), PlanetNameSelector)) 34 | { 35 | Console.WriteLine(planet); 36 | } 37 | 38 | // This code produces the following output: 39 | // Planet { Name = Venus, Type = Rock, OrderFromSun = 2 } 40 | // 41 | 42 | Console.WriteLine(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/bad/sln_no_proj/some_code/Program.cs: -------------------------------------------------------------------------------- 1 | using SolarSystem; 2 | 3 | Program.DistinctByExample(); 4 | Program.ExceptByExample(); 5 | Program.IntersectByExample(); 6 | Program.UnionByExample(); 7 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/finished/toll-calculator/ExternalSystems.cs: -------------------------------------------------------------------------------- 1 | namespace ConsumerVehicleRegistration 2 | { 3 | public class Car 4 | { 5 | public int Passengers { get; set; } 6 | } 7 | } 8 | 9 | namespace CommercialRegistration 10 | { 11 | public class DeliveryTruck 12 | { 13 | public int GrossWeightClass { get; set; } 14 | } 15 | } 16 | 17 | namespace LiveryRegistration 18 | { 19 | public class Taxi 20 | { 21 | public int Fares { get; set; } 22 | } 23 | 24 | public class Bus 25 | { 26 | public int Capacity { get; set; } 27 | public int Riders { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/finished/toll-calculator/toll-calculator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net6.0 6 | toll_calculator 7 | enable 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/start/toll-calculator/ExternalSystems.cs: -------------------------------------------------------------------------------- 1 | namespace ConsumerVehicleRegistration 2 | { 3 | public class Car 4 | { 5 | public int Passengers { get; set; } 6 | } 7 | } 8 | 9 | namespace CommercialRegistration 10 | { 11 | public class DeliveryTruck 12 | { 13 | public int GrossWeightClass { get; set; } 14 | } 15 | } 16 | 17 | namespace LiveryRegistration 18 | { 19 | public class Taxi 20 | { 21 | public int Fares { get; set; } 22 | } 23 | 24 | public class Bus 25 | { 26 | public int Capacity { get; set; } 27 | public int Riders { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/start/toll-calculator/toll-calculator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | toll_calculator 8 | enable 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/cpp/MyForm.cpp: -------------------------------------------------------------------------------- 1 | #include "MyForm.h" 2 | 3 | using namespace System; 4 | using namespace System::Windows::Forms; 5 | [STAThreadAttribute] 6 | 7 | void main(array^ args) { 8 | Application::SetCompatibleTextRenderingDefault(false); 9 | Application::EnableVisualStyles(); 10 | project::MyForm frm; 11 | Application::Run(%frm); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/cpp/Student.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace project { 3 | 4 | using namespace System; 5 | using namespace System::Collections; 6 | public ref class Student 7 | { 8 | private: 9 | ArrayList^ _studentSubjects = gcnew ArrayList(); 10 | public: 11 | String^ StudentName = ""; 12 | 13 | ArrayList^ StudentSubjects = _studentSubjects; 14 | 15 | Student(String^ studentName) 16 | { 17 | StudentName = studentName; 18 | } 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/cpp/Subject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace project { 3 | using namespace System; 4 | using namespace System::Collections; 5 | 6 | public ref class Subject 7 | { 8 | private: 9 | ArrayList^ _subjectTextbooks = gcnew ArrayList(); 10 | public: 11 | String^ SubjectID = ""; 12 | 13 | ArrayList^ SubjectTextbooks = _subjectTextbooks; 14 | 15 | Subject(String^ subjectID) 16 | { 17 | SubjectID = subjectID; 18 | } 19 | }; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/cpp/TextBook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | namespace project { 3 | using namespace System; 4 | using namespace System::Collections; 5 | 6 | public ref class TextBook 7 | { 8 | public: 9 | String^ TextBookID = ""; 10 | 11 | TextBook(String^ textBookID) 12 | { 13 | TextBookID = textBookID; 14 | } 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/cpp/snippets.5000.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "dotnet", 3 | "expectederrors": [ 4 | { 5 | "file": "snippets\\good\\deeper-path\\three_projs\\cpp\\project.vcxproj", 6 | "line": 33, 7 | "column": 3, 8 | "error": "MSB4019" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/cs/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace project 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new Form1());async; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/cs/Student.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace project 4 | { 5 | // The basic Student class. 6 | public class Student 7 | { 8 | protected ArrayList _studentSubjects = new ArrayList(); 9 | 10 | public Student(string studentName) 11 | { 12 | StudentName = studentName; 13 | } 14 | 15 | public string StudentName { get; set; } = ""; 16 | 17 | public ArrayList StudentSubjects => _studentSubjects; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/cs/Subject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | namespace project 4 | { 5 | // The basic student Subject class. 6 | public class Subject 7 | { 8 | protected ArrayList _subjectTextbooks = new ArrayList(); 9 | 10 | public Subject(string subjectID) 11 | { 12 | SubjectID = subjectID; 13 | } 14 | 15 | public string SubjectID { get; set; } = ""; 16 | 17 | public ArrayList SubjectTextbooks => _subjectTextbooks; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/cs/TextBook.cs: -------------------------------------------------------------------------------- 1 | namespace project 2 | { 3 | public class TextBook 4 | { 5 | 6 | public TextBook(string textBookID) 7 | { 8 | TextBookID = textBookID; 9 | } 10 | 11 | public string TextBookID { get; set; } = ""; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/cs/snippets.5000.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "dotnet", 3 | "expectederrors": [ 4 | { 5 | "file": "snippets\\good\\deeper-path\\three_projs\\cs\\Program.cs", 6 | "line": 19, 7 | "error": "CS0201" 8 | }, 9 | { 10 | "file": "snippets\\good\\deeper-path\\three_projs\\cs\\program.cs", 11 | "line": 19, 12 | "error": "CS0103" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/vb/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/vb/My Project/Application.myapp: -------------------------------------------------------------------------------- 1 |  2 | 3 | true 4 | Form1 5 | false 6 | 0 7 | true 8 | 0 9 | 0 10 | true 11 | 12 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/vb/My Project/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/vb/Student.vb: -------------------------------------------------------------------------------- 1 | Namespace project 2 | Public Class Student 3 | Protected _studentSubjects As ArrayList = New ArrayList() 4 | 5 | Public Sub New(studentName As String) 6 | Me.StudentName = studentName 7 | End Sub 8 | 9 | Public Property StudentName As String = "" 10 | 11 | Public ReadOnly Property StudentSubjects As ArrayList 12 | Get 13 | Return _studentSubjects 14 | End Get 15 | End Property 16 | End Class 17 | End Namespace 18 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/vb/Subject.vb: -------------------------------------------------------------------------------- 1 | Namespace project 2 | Public Class Subject 3 | Protected _subjectTextbooks As ArrayList = New ArrayList() 4 | 5 | Public Sub New(ByVal subjectID As String) 6 | Me.SubjectID = subjectID 7 | End Sub 8 | 9 | Public Property SubjectID As String = "" 10 | 11 | Public ReadOnly Property SubjectTextbooks As ArrayList 12 | Get 13 | Return _subjectTextbooks 14 | End Get 15 | End Property 16 | End Class 17 | End Namespace 18 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/deeper-path/three_projs/vb/TextBook.vb: -------------------------------------------------------------------------------- 1 | Namespace project 2 | Public Class TextBook 3 | Public Sub New(textBookID As String) 4 | Me.TextBookID = textBookID 5 | End Sub 6 | 7 | Public Property TextBookID As String = "" 8 | End Class 9 | End Namespace 10 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/normal/asandis/asandis.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/normal/csharp_project/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | Console.WriteLine("Hello, World!"); 3 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/normal/csharp_project/app1.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/normal/csharp_project/snippets.5000.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/docs-tools/e88a4c229f2fc2dbe5cfa3ffabbcef8489ffba50/snippets5000/PullRequestSimulations/snippets/good/normal/csharp_project/snippets.5000.json -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/normal/deleted_code/snippets.5000.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnet/docs-tools/e88a4c229f2fc2dbe5cfa3ffabbcef8489ffba50/snippets5000/PullRequestSimulations/snippets/good/normal/deleted_code/snippets.5000.json -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/normal/nullablepatternmatching/nullablepatternmatching.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/normal/patternmatching/patternmatching.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/normal/vb_project/Program.vb: -------------------------------------------------------------------------------- 1 | Imports System 2 | 3 | Module Program 4 | Sub Main(args As String()) 5 | Console.WriteLine("Hello World!") 6 | End Sub 7 | End Module 8 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/normal/vb_project/app1.vbproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | vb_project 6 | net7.0 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/extensions/linq.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | true 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/partition/Program.cs: -------------------------------------------------------------------------------- 1 | int chunkNumber = 1; 2 | foreach (int[] chunk in Enumerable.Range(0, 8).Chunk(3)) 3 | { 4 | Console.WriteLine($"Chunk {chunkNumber++}:"); 5 | foreach (int item in chunk) 6 | { 7 | Console.WriteLine($" {item}"); 8 | } 9 | 10 | Console.WriteLine(); 11 | } 12 | // This code produces the following output: 13 | // Chunk 1: 14 | // 0 15 | // 1 16 | // 2 17 | // 18 | //Chunk 2: 19 | // 3 20 | // 4 21 | // 5 22 | // 23 | //Chunk 3: 24 | // 6 25 | // 7 26 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/partition/partition.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | true 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/projection/Program.ZipResult.cs: -------------------------------------------------------------------------------- 1 | public static partial class Program 2 | { 3 | internal static void ZipResultExample( 4 | IEnumerable numbers, 5 | IEnumerable letters) 6 | { 7 | Console.WriteLine("Zip (TFirst, TSecond, Func):"); 8 | 9 | // 10 | foreach (string result in 11 | numbers.Zip(letters, (number, letter) => $"{number} = {letter} ({(int)letter})")) 12 | { 13 | Console.WriteLine(result); 14 | } 15 | // This code produces the following output: 16 | // 1 = A (65) 17 | // 2 = B (66) 18 | // 3 = C (67) 19 | // 4 = D (68) 20 | // 5 = E (69) 21 | // 6 = F (70) 22 | // 23 | 24 | Console.WriteLine(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/projection/Program.ZipTriple.cs: -------------------------------------------------------------------------------- 1 | public static partial class Program 2 | { 3 | internal static void ZipTripleExample( 4 | IEnumerable numbers, 5 | IEnumerable letters, 6 | IEnumerable emoji) 7 | { 8 | Console.WriteLine("Zip (TFirst, TSecond, TThird):"); 9 | 10 | // 11 | foreach ((int number, char letter, string em) in numbers.Zip(letters, emoji)) 12 | { 13 | Console.WriteLine( 14 | $"Number: {number} is zipped with letter: '{letter}' and emoji: {em}"); 15 | } 16 | // This code produces the following output: 17 | // Number: 1 is zipped with letter: 'A' and emoji: 🤓 18 | // Number: 2 is zipped with letter: 'B' and emoji: 🔥 19 | // Number: 3 is zipped with letter: 'C' and emoji: 🎉 20 | // Number: 4 is zipped with letter: 'D' and emoji: 👀 21 | // Number: 5 is zipped with letter: 'E' and emoji: ⭐ 22 | // Number: 6 is zipped with letter: 'F' and emoji: 💜 23 | // 24 | 25 | Console.WriteLine(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/projection/Program.ZipTuple.cs: -------------------------------------------------------------------------------- 1 | public static partial class Program 2 | { 3 | internal static void ZipTupleExample( 4 | IEnumerable numbers, 5 | IEnumerable letters) 6 | { 7 | Console.WriteLine("Zip (TFirst, TSecond):"); 8 | 9 | // 10 | foreach ((int number, char letter) in numbers.Zip(letters)) 11 | { 12 | Console.WriteLine($"Number: {number} zipped with letter: '{letter}'"); 13 | } 14 | // This code produces the following output: 15 | // Number: 1 zipped with letter: 'A' 16 | // Number: 2 zipped with letter: 'B' 17 | // Number: 3 zipped with letter: 'C' 18 | // Number: 4 zipped with letter: 'D' 19 | // Number: 5 zipped with letter: 'E' 20 | // Number: 6 zipped with letter: 'F' 21 | // 22 | 23 | Console.WriteLine(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/projection/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | Console.OutputEncoding = System.Text.Encoding.UTF8; 4 | 5 | // 6 | // An int array with 7 elements. 7 | IEnumerable numbers = new[] 8 | { 9 | 1, 2, 3, 4, 5, 6, 7 10 | }; 11 | // A char array with 6 elements. 12 | IEnumerable letters = new[] 13 | { 14 | 'A', 'B', 'C', 'D', 'E', 'F' 15 | }; 16 | // 17 | // 18 | // A string array with 8 elements. 19 | IEnumerable emoji = new[] 20 | { 21 | "🤓", "🔥", "🎉", "👀", "⭐", "💜", "✔", "💯" 22 | }; 23 | // 24 | 25 | Program.ZipTupleExample(numbers, letters); 26 | Program.ZipTripleExample(numbers, letters, emoji); 27 | Program.ZipResultExample(numbers, letters); 28 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/projection/projection.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | true 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/set-operators/Planet.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | record Planet( 4 | string Name, 5 | PlanetType Type, 6 | int OrderFromSun) 7 | { 8 | public static readonly Planet Mercury = 9 | new(nameof(Mercury), PlanetType.Rock, 1); 10 | 11 | public static readonly Planet Venus = 12 | new(nameof(Venus), PlanetType.Rock, 2); 13 | 14 | public static readonly Planet Earth = 15 | new(nameof(Earth), PlanetType.Rock, 3); 16 | 17 | public static readonly Planet Mars = 18 | new(nameof(Mars), PlanetType.Rock, 4); 19 | 20 | public static readonly Planet Jupiter = 21 | new(nameof(Jupiter), PlanetType.Gas, 5); 22 | 23 | public static readonly Planet Saturn = 24 | new(nameof(Saturn), PlanetType.Gas, 6); 25 | 26 | public static readonly Planet Uranus = 27 | new(nameof(Uranus), PlanetType.Liquid, 7); 28 | 29 | public static readonly Planet Neptune = 30 | new(nameof(Neptune), PlanetType.Liquid, 8); 31 | 32 | // Yes, I know... not technically a planet anymore 33 | public static readonly Planet Pluto = 34 | new(nameof(Pluto), PlanetType.Ice, 9); 35 | } 36 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/set-operators/PlanetType.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | enum PlanetType 4 | { 5 | Rock, 6 | Ice, 7 | Gas, 8 | Liquid 9 | }; 10 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/set-operators/Program.DistinctBy.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | public static partial class Program 4 | { 5 | internal static void DistinctByExample() 6 | { 7 | Console.WriteLine("DistinctBy:"); 8 | 9 | // 10 | Planet[] planets = 11 | { 12 | Planet.Mercury, 13 | Planet.Venus, 14 | Planet.Earth, 15 | Planet.Mars, 16 | Planet.Jupiter, 17 | Planet.Saturn, 18 | Planet.Uranus, 19 | Planet.Neptune, 20 | Planet.Pluto 21 | }; 22 | // 23 | 24 | // 25 | foreach (Planet planet in planets.DistinctBy(p => p.Type)) 26 | { 27 | Console.WriteLine(planet); 28 | } 29 | 30 | // This code produces the following output: 31 | // Planet { Name = Mercury, Type = Rock, OrderFromSun = 1 } 32 | // Planet { Name = Jupiter, Type = Gas, OrderFromSun = 5 } 33 | // Planet { Name = Uranus, Type = Liquid, OrderFromSun = 7 } 34 | // Planet { Name = Pluto, Type = Ice, OrderFromSun = 9 } 35 | // 36 | 37 | Console.WriteLine(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/set-operators/Program.ExceptBy.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | public static partial class Program 4 | { 5 | internal static void ExceptByExample() 6 | { 7 | Console.WriteLine("ExceptBy:"); 8 | 9 | // 10 | Planet[] planets = 11 | { 12 | Planet.Mercury, 13 | Planet.Venus, 14 | Planet.Earth, 15 | Planet.Jupiter 16 | }; 17 | 18 | Planet[] morePlanets = 19 | { 20 | Planet.Mercury, 21 | Planet.Earth, 22 | Planet.Mars, 23 | Planet.Jupiter 24 | }; 25 | // 26 | 27 | // 28 | // A shared "keySelector" 29 | static string PlanetNameSelector(Planet planet) => planet.Name; 30 | 31 | foreach (Planet planet in 32 | planets.ExceptBy( 33 | morePlanets.Select(PlanetNameSelector), PlanetNameSelector)) 34 | { 35 | Console.WriteLine(planet); 36 | } 37 | 38 | // This code produces the following output: 39 | // Planet { Name = Venus, Type = Rock, OrderFromSun = 2 } 40 | // 41 | 42 | Console.WriteLine(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/set-operators/Program.cs: -------------------------------------------------------------------------------- 1 | using SolarSystem; 2 | 3 | Program.DistinctByExample(); 4 | Program.ExceptByExample(); 5 | Program.IntersectByExample(); 6 | Program.UnionByExample(); 7 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/lots-o-projects/set-operators/set-operators.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | true 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/single-project/set-operators/Planet.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | record Planet( 4 | string Name, 5 | PlanetType Type, 6 | int OrderFromSun) 7 | { 8 | public static readonly Planet Mercury = 9 | new(nameof(Mercury), PlanetType.Rock, 1); 10 | 11 | public static readonly Planet Venus = 12 | new(nameof(Venus), PlanetType.Rock, 2); 13 | 14 | public static readonly Planet Earth = 15 | new(nameof(Earth), PlanetType.Rock, 3); 16 | 17 | public static readonly Planet Mars = 18 | new(nameof(Mars), PlanetType.Rock, 4); 19 | 20 | public static readonly Planet Jupiter = 21 | new(nameof(Jupiter), PlanetType.Gas, 5); 22 | 23 | public static readonly Planet Saturn = 24 | new(nameof(Saturn), PlanetType.Gas, 6); 25 | 26 | public static readonly Planet Uranus = 27 | new(nameof(Uranus), PlanetType.Liquid, 7); 28 | 29 | public static readonly Planet Neptune = 30 | new(nameof(Neptune), PlanetType.Liquid, 8); 31 | 32 | // Yes, I know... not technically a planet anymore 33 | public static readonly Planet Pluto = 34 | new(nameof(Pluto), PlanetType.Ice, 9); 35 | } 36 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/single-project/set-operators/PlanetType.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | enum PlanetType 4 | { 5 | Rock, 6 | Ice, 7 | Gas, 8 | Liquid 9 | }; 10 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/single-project/set-operators/Program.DistinctBy.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | public static partial class Program 4 | { 5 | internal static void DistinctByExample() 6 | { 7 | Console.WriteLine("DistinctBy:"); 8 | 9 | // 10 | Planet[] planets = 11 | { 12 | Planet.Mercury, 13 | Planet.Venus, 14 | Planet.Earth, 15 | Planet.Mars, 16 | Planet.Jupiter, 17 | Planet.Saturn, 18 | Planet.Uranus, 19 | Planet.Neptune, 20 | Planet.Pluto 21 | }; 22 | // 23 | 24 | // 25 | foreach (Planet planet in planets.DistinctBy(p => p.Type)) 26 | { 27 | Console.WriteLine(planet); 28 | } 29 | 30 | // This code produces the following output: 31 | // Planet { Name = Mercury, Type = Rock, OrderFromSun = 1 } 32 | // Planet { Name = Jupiter, Type = Gas, OrderFromSun = 5 } 33 | // Planet { Name = Uranus, Type = Liquid, OrderFromSun = 7 } 34 | // Planet { Name = Pluto, Type = Ice, OrderFromSun = 9 } 35 | // 36 | 37 | Console.WriteLine(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/single-project/set-operators/Program.ExceptBy.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | public static partial class Program 4 | { 5 | internal static void ExceptByExample() 6 | { 7 | Console.WriteLine("ExceptBy:"); 8 | 9 | // 10 | Planet[] planets = 11 | { 12 | Planet.Mercury, 13 | Planet.Venus, 14 | Planet.Earth, 15 | Planet.Jupiter 16 | }; 17 | 18 | Planet[] morePlanets = 19 | { 20 | Planet.Mercury, 21 | Planet.Earth, 22 | Planet.Mars, 23 | Planet.Jupiter 24 | }; 25 | // 26 | 27 | // 28 | // A shared "keySelector" 29 | static string PlanetNameSelector(Planet planet) => planet.Name; 30 | 31 | foreach (Planet planet in 32 | planets.ExceptBy( 33 | morePlanets.Select(PlanetNameSelector), PlanetNameSelector)) 34 | { 35 | Console.WriteLine(planet); 36 | } 37 | 38 | // This code produces the following output: 39 | // Planet { Name = Venus, Type = Rock, OrderFromSun = 2 } 40 | // 41 | 42 | Console.WriteLine(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/single-project/set-operators/Program.cs: -------------------------------------------------------------------------------- 1 | using SolarSystem; 2 | 3 | Program.DistinctByExample(); 4 | Program.ExceptByExample(); 5 | Program.IntersectByExample(); 6 | Program.UnionByExample(); 7 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/single-project/set-operators/set-operators.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | true 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/sln_odd_proj/file.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31612.314 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Global 7 | GlobalSection(SolutionProperties) = preSolution 8 | HideSolutionNode = FALSE 9 | EndGlobalSection 10 | GlobalSection(ExtensibilityGlobals) = postSolution 11 | SolutionGuid = {DEB164F0-9F8F-4880-ACCF-994BE3CD9105} 12 | EndGlobalSection 13 | EndGlobal 14 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/sln_odd_proj/some_code/Planet.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | record Planet( 4 | string Name, 5 | PlanetType Type, 6 | int OrderFromSun) 7 | { 8 | public static readonly Planet Mercury = 9 | new(nameof(Mercury), PlanetType.Rock, 1); 10 | 11 | public static readonly Planet Venus = 12 | new(nameof(Venus), PlanetType.Rock, 2); 13 | 14 | public static readonly Planet Earth = 15 | new(nameof(Earth), PlanetType.Rock, 3); 16 | 17 | public static readonly Planet Mars = 18 | new(nameof(Mars), PlanetType.Rock, 4); 19 | 20 | public static readonly Planet Jupiter = 21 | new(nameof(Jupiter), PlanetType.Gas, 5); 22 | 23 | public static readonly Planet Saturn = 24 | new(nameof(Saturn), PlanetType.Gas, 6); 25 | 26 | public static readonly Planet Uranus = 27 | new(nameof(Uranus), PlanetType.Liquid, 7); 28 | 29 | public static readonly Planet Neptune = 30 | new(nameof(Neptune), PlanetType.Liquid, 8); 31 | 32 | // Yes, I know... not technically a planet anymore 33 | public static readonly Planet Pluto = 34 | new(nameof(Pluto), PlanetType.Ice, 9); 35 | } 36 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/sln_odd_proj/some_code/PlanetType.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | enum PlanetType 4 | { 5 | Rock, 6 | Ice, 7 | Gas, 8 | Liquid 9 | }; 10 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/sln_odd_proj/some_code/Program.DistinctBy.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | public static partial class Program 4 | { 5 | internal static void DistinctByExample() 6 | { 7 | Console.WriteLine("DistinctBy:"); 8 | 9 | // 10 | Planet[] planets = 11 | { 12 | Planet.Mercury, 13 | Planet.Venus, 14 | Planet.Earth, 15 | Planet.Mars, 16 | Planet.Jupiter, 17 | Planet.Saturn, 18 | Planet.Uranus, 19 | Planet.Neptune, 20 | Planet.Pluto 21 | }; 22 | // 23 | 24 | // 25 | foreach (Planet planet in planets.DistinctBy(p => p.Type)) 26 | { 27 | Console.WriteLine(planet); 28 | } 29 | 30 | // This code produces the following output: 31 | // Planet { Name = Mercury, Type = Rock, OrderFromSun = 1 } 32 | // Planet { Name = Jupiter, Type = Gas, OrderFromSun = 5 } 33 | // Planet { Name = Uranus, Type = Liquid, OrderFromSun = 7 } 34 | // Planet { Name = Pluto, Type = Ice, OrderFromSun = 9 } 35 | // 36 | 37 | Console.WriteLine(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/sln_odd_proj/some_code/Program.ExceptBy.cs: -------------------------------------------------------------------------------- 1 | namespace SolarSystem; 2 | 3 | public static partial class Program 4 | { 5 | internal static void ExceptByExample() 6 | { 7 | Console.WriteLine("ExceptBy:"); 8 | 9 | // 10 | Planet[] planets = 11 | { 12 | Planet.Mercury, 13 | Planet.Venus, 14 | Planet.Earth, 15 | Planet.Jupiter 16 | }; 17 | 18 | Planet[] morePlanets = 19 | { 20 | Planet.Mercury, 21 | Planet.Earth, 22 | Planet.Mars, 23 | Planet.Jupiter 24 | }; 25 | // 26 | 27 | // 28 | // A shared "keySelector" 29 | static string PlanetNameSelector(Planet planet) => planet.Name; 30 | 31 | foreach (Planet planet in 32 | planets.ExceptBy( 33 | morePlanets.Select(PlanetNameSelector), PlanetNameSelector)) 34 | { 35 | Console.WriteLine(planet); 36 | } 37 | 38 | // This code produces the following output: 39 | // Planet { Name = Venus, Type = Rock, OrderFromSun = 2 } 40 | // 41 | 42 | Console.WriteLine(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/sln_odd_proj/some_code/Program.cs: -------------------------------------------------------------------------------- 1 | using SolarSystem; 2 | 3 | Program.DistinctByExample(); 4 | Program.ExceptByExample(); 5 | Program.IntersectByExample(); 6 | Program.UnionByExample(); 7 | -------------------------------------------------------------------------------- /snippets5000/PullRequestSimulations/snippets/good/solutions/sln_odd_proj/some_code/project1.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets5000/Snippets5000/DiscoveryResult.cs: -------------------------------------------------------------------------------- 1 | namespace Snippets5000 2 | { 3 | internal struct DiscoveryResult 4 | { 5 | public const int RETURN_GOOD = 0; 6 | public const int RETURN_NOPROJ = 1; 7 | public const int RETURN_TOOMANY = 2; 8 | public const int RETURN_SLN_NOPROJ = 3; 9 | public const int RETURN_SLN_PROJ_MISSING = 4; 10 | 11 | public const int RETURN_TEMP_SLNFOUND = 99; 12 | 13 | public readonly int Code { get; init; } 14 | public readonly string InputFile { get; init; } 15 | public readonly string DiscoveredFile { get; init; } 16 | 17 | public DiscoveryResult(int code, string inputFile, string discoveredFile) 18 | { 19 | Code = code; 20 | InputFile = inputFile; 21 | DiscoveredFile = discoveredFile; 22 | } 23 | 24 | public override string ToString() => 25 | $"{Code}|{InputFile}|{DiscoveredFile}"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /snippets5000/Snippets5000/Extensions.cs: -------------------------------------------------------------------------------- 1 | internal static class Extensions 2 | { 3 | // TRUE if "projectPath" is a child of one of the entries in folders 4 | internal static bool ContainedInOneOf(this string projectPath, IEnumerable folders) 5 | { 6 | foreach (var folder in folders) 7 | { 8 | if (projectPath.Contains(folder)) 9 | { 10 | return true; 11 | } 12 | } 13 | return false; 14 | } 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /snippets5000/Snippets5000/PullRequestSimulationsHelpers/ChangeItem.cs: -------------------------------------------------------------------------------- 1 | namespace PullRequestSimulations; 2 | 3 | /// 4 | /// A data type for the data.json file. Represents a pull request change item request. 5 | /// 6 | public readonly struct ChangeItem 7 | { 8 | /// 9 | /// The type of change associated with this item. 10 | /// 11 | public ChangeItemType ItemType { get; init; } 12 | 13 | /// 14 | /// The path to the file affected by this item. 15 | /// 16 | public string Path { get; init; } 17 | 18 | /// 19 | /// Creates a new change item with the specified values. 20 | /// 21 | /// The type of change. 22 | /// The path to the file affected by this item. 23 | public ChangeItem(ChangeItemType itemType, string path) 24 | { 25 | ItemType = itemType; 26 | Path = path; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /snippets5000/Snippets5000/PullRequestSimulationsHelpers/ChangeItemType.cs: -------------------------------------------------------------------------------- 1 | namespace PullRequestSimulations; 2 | 3 | /// 4 | /// A data type for the data.json file. Represents a pull request change item action. 5 | /// 6 | public enum ChangeItemType 7 | { 8 | /// 9 | /// Create a file. 10 | /// 11 | Create, 12 | 13 | /// 14 | /// Modify a file. 15 | /// 16 | Edit, 17 | 18 | /// 19 | /// Remove a file. 20 | /// 21 | Delete 22 | } -------------------------------------------------------------------------------- /snippets5000/Snippets5000/PullRequestSimulationsHelpers/ExpectedResult.cs: -------------------------------------------------------------------------------- 1 | namespace PullRequestSimulations; 2 | 3 | /// 4 | /// A data type for the data.json file. A result from scanning a pull request change item. 5 | /// 6 | public readonly struct ExpectedResult 7 | { 8 | /// 9 | /// The result code from the scanner. 10 | /// 11 | /// These map to the constant values defined in the type. 12 | public int ResultCode { get; init; } 13 | 14 | /// 15 | /// The path to a project file 16 | /// 17 | public string DiscoveredProject { get; init; } 18 | 19 | /// 20 | /// Creates a new result with the specified code and project. 21 | /// 22 | /// The result code. 23 | /// The path to the project. 24 | public ExpectedResult(int resultCode, string discoveredProject) 25 | { 26 | ResultCode = resultCode; 27 | DiscoveredProject = discoveredProject; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /snippets5000/Snippets5000/Snippets5000.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net9.0 6 | enable 7 | enable 8 | 9 | 4.3.0.0 10 | Snippets 5000 11 | Andy De George 12 | Microsoft 13 | 14 | $(DefineConstants);LINUX 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /snippets5000/Snippets5000/TestingProjectList.cs: -------------------------------------------------------------------------------- 1 | namespace Snippets5000; 2 | 3 | /// 4 | /// This class is used to process an item from the data.json file in the MSTest project, simulating a GitHub PR. 5 | /// 6 | internal class TestingProjectList 7 | { 8 | private readonly string _testId; 9 | private readonly string _rootDir; 10 | private readonly string _testDataFile; 11 | 12 | internal TestingProjectList(string testId, string testDataFile, string rootDir) 13 | { 14 | _testId = testId; 15 | _rootDir = rootDir; 16 | _testDataFile = testDataFile; 17 | } 18 | 19 | internal IEnumerable GenerateBuildList() 20 | { 21 | var tests = PullRequestSimulations.PullRequest.LoadTests(_testDataFile); 22 | 23 | foreach (var item in tests.Where(t => t.Name.Equals(_testId, StringComparison.InvariantCultureIgnoreCase)).First().Items) 24 | { 25 | DiscoveryResult? resultValue = PullRequestProcessor.GenerateItemResult(_rootDir, item.Path); 26 | 27 | if (resultValue != null) 28 | yield return resultValue.Value; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /whatsnew.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/dotnet/sdk:9.0 as build-env 2 | # Copy everything and publish the release (publish implicitly restores and builds) 3 | WORKDIR /app 4 | COPY . ./ 5 | RUN dotnet publish "WhatsNew.Cli/WhatsNew.Cli.csproj" -c Release -o out --no-self-contained 6 | 7 | # Relayer the .NET SDK, anew with the build output 8 | FROM mcr.microsoft.com/dotnet/sdk:9.0 9 | COPY --from=build-env /app/out . 10 | ENTRYPOINT [ "dotnet", "/WhatsNew.dll" ] --------------------------------------------------------------------------------