diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6d12ed1..dcecbf0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,8 +9,6 @@ on: - synchronize - reopened - closed - branches: - - main env: IS_RELEASE_CANDIDATE: >- ${{ @@ -31,11 +29,11 @@ jobs: runs-on: ubuntu-latest steps: - name: Check Out - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Setup Dot Net Version - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: - dotnet-version: 8.0.302 + dotnet-version: 10.x - name: Restore run: dotnet restore - name: Build @@ -58,7 +56,7 @@ jobs: contains(github.event.pull_request.labels.*.name, 'RELEASES') steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v5 with: token: ${{ secrets.PAT_FOR_TAGGING }} - name: Configure Git @@ -130,11 +128,11 @@ jobs: if: needs.add_tag.result == 'success' steps: - name: Check out - uses: actions/checkout@v3 + uses: actions/checkout@v5 - name: Setup .Net - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: - dotnet-version: 7.0.201 + dotnet-version: 10.0.100 - name: Restore run: dotnet restore - name: Build diff --git a/.github/workflows/prLinter.yml b/.github/workflows/prLinter.yml new file mode 100644 index 0000000..06811ab --- /dev/null +++ b/.github/workflows/prLinter.yml @@ -0,0 +1,97 @@ +name: PR Linter +on: + pull_request: + types: + - opened + - synchronize + - reopened + - edited + - closed +jobs: + require_issue_or_task: + runs-on: ubuntu-latest + steps: + - name: Check out + uses: actions/checkout@v5 + - name: Get PR Information + id: get_pr_info + uses: actions/github-script@v8 + with: + script: >2- + const pr = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number + }); + + const prOwner = pr.data.user.login || ""; + const prBody = pr.data.body || ""; + core.setOutput("prOwner", prOwner); + core.setOutput("description", prBody); + console.log(`PR Owner: ${prOwner}`); + console.log(`PR Body: ${prBody}`); + - name: Check For Associated Issues Or Tasks + id: check_for_issues_or_tasks + if: ${{ !contains(',,', format(',{0},', steps.get_pr_info.outputs.prOwner)) }} + env: + PR_BODY: ${{ steps.get_pr_info.outputs.description }} + run: >2- + if [[ -z "${PR_BODY:-}" ]]; then + echo "Error: PR description does not contain any links to issue(s)/task(s) (e.g., 'closes #123' / 'closes AB#123' / 'fixes #123' / 'fixes AB#123')." + exit 1 + fi + + NORMALIZED_PR_BODY=$(printf '%s' "$PR_BODY" | tr '\r\n' ' ' | tr -s ' ') + + if printf '%s' "$NORMALIZED_PR_BODY" | grep -Piq "(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\s*(\[#[0-9]+\]|#[0-9]+|\[AB#[0-9]+\]|AB#[0-9]+)"; then + echo "Valid PR description." + else + echo "Error: PR description does not contain any links to issue(s)/task(s) (e.g., 'closes #123' / 'closes AB#123' / 'fixes #123' / 'fixes AB#123')." + exit 1 + fi + shell: bash + permissions: + contents: read + pull-requests: read + set_author_as_pr_assignee: + runs-on: ubuntu-latest + if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} + steps: + - name: Set Author As PR Assignee + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: > + const pr = context.payload.pull_request; + + if (!pr) { + console.log('No pull request context available.'); + return; + } + + + const author = pr.user.login; + + if (author.endsWith('[bot]')) { + console.log(`Skipping bot author: ${author}`); + return; + } + + + console.log(`Assigning PR to author: ${author}`); + + + try { + await github.rest.issues.addAssignees({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + assignees: [author] + }); + } catch (error) { + console.log(`Unable to assign ${author} as PR assignee: ${error.message}`); + } + permissions: + contents: read + issues: write + pull-requests: write diff --git a/NHSISL.LibPostalClient.Infrastructure/Program.cs b/NHSISL.LibPostalClient.Infrastructure/Program.cs index dff982b..2cb9f05 100644 --- a/NHSISL.LibPostalClient.Infrastructure/Program.cs +++ b/NHSISL.LibPostalClient.Infrastructure/Program.cs @@ -10,8 +10,11 @@ internal class Program { static void Main(string[] args) { + Environment.CurrentDirectory = AppContext.BaseDirectory; + var scriptGenerationService = new ScriptGenerationService(); scriptGenerationService.GenerateBuildScript(); + scriptGenerationService.GeneratePrLinterScript(); } } } \ No newline at end of file diff --git a/NHSISL.LibPostalClient.Infrastructure/Services/ScriptGenerationService.cs b/NHSISL.LibPostalClient.Infrastructure/Services/ScriptGenerationService.cs index b861c37..e9d3035 100644 --- a/NHSISL.LibPostalClient.Infrastructure/Services/ScriptGenerationService.cs +++ b/NHSISL.LibPostalClient.Infrastructure/Services/ScriptGenerationService.cs @@ -5,7 +5,7 @@ using ADotNet.Clients; using ADotNet.Models.Pipelines.GithubPipelines.DotNets; using ADotNet.Models.Pipelines.GithubPipelines.DotNets.Tasks; -using ADotNet.Models.Pipelines.GithubPipelines.DotNets.Tasks.SetupDotNetTaskV3s; +using ADotNet.Models.Pipelines.GithubPipelines.DotNets.Tasks.SetupDotNetTaskV5s; namespace NHSISL.LibPostalClient.Infrastructure.Services { @@ -33,8 +33,7 @@ public void GenerateBuildScript() PullRequest = new PullRequestEvent { - Types = new string[] { "opened", "synchronize", "reopened", "closed" }, - Branches = new string[] { branchName } + Types = new string[] { "opened", "synchronize", "reopened", "closed" } } }, @@ -43,7 +42,6 @@ public void GenerateBuildScript() { "IS_RELEASE_CANDIDATE", EnvironmentVariables.IsGitHubReleaseCandidate() } }, - Jobs = new Dictionary { { @@ -54,18 +52,18 @@ public void GenerateBuildScript() Steps = new List { - new CheckoutTaskV3 + new CheckoutTaskV5 { Name = "Check Out" }, - new SetupDotNetTaskV3 + new SetupDotNetTaskV5 { Name = "Setup Dot Net Version", - With = new TargetDotNetVersionV3 + With = new TargetDotNetVersionV5 { - DotNetVersion = "8.0.302" + DotNetVersion = "10.x" } }, @@ -88,7 +86,7 @@ public void GenerateBuildScript() }, { "add_tag", - new TagJob( + new TagJobV2( runsOn: BuildMachines.UbuntuLatest, dependsOn: "build", projectRelativePath: "NHSISL.LibPostalClient/NHSISL.LibPostalClient.csproj", @@ -97,10 +95,11 @@ public void GenerateBuildScript() }, { "publish", - new PublishJob( + new PublishJobV4( runsOn: BuildMachines.UbuntuLatest, dependsOn: "add_tag", - nugetApiKey: "${{ secrets.NUGET_ACCESS }}") + nugetApiKey: "${{ secrets.NUGET_ACCESS }}", + dotNetVersion: "10.0.100") } } }; @@ -117,5 +116,45 @@ public void GenerateBuildScript() githubPipeline, path: buildScriptPath); } + + public void GeneratePrLinterScript() + { + var githubPipeline = new GithubPipeline + { + Name = "PR Linter", + + OnEvents = new Events + { + PullRequest = new PullRequestEvent + { + Types = new string[] { "opened", "synchronize", "reopened", "edited", "closed" } + } + }, + + Jobs = new Dictionary + { + { + "require_issue_or_task", + new RequireIssueOrTaskJobV2() + }, + { + "set_author_as_pr_assignee", + new SetAuthorAsPrAssigneeJobV2(BuildMachines.UbuntuLatest) + } + } + }; + + string prLinterScriptPath = "../../../../.github/workflows/prLinter.yml"; + string directoryPath = Path.GetDirectoryName(prLinterScriptPath); + + if (!Directory.Exists(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + this.adotNetClient.SerializeAndWriteToFile( + githubPipeline, + path: prLinterScriptPath); + } } } diff --git a/NHSISL.LibPostalClient.Tests.Acceptance/NHSISL - Backup.LibPostalClient.Tests.Acceptance.csproj b/NHSISL.LibPostalClient.Tests.Acceptance/NHSISL - Backup.LibPostalClient.Tests.Acceptance.csproj index 778975a..7348513 100644 --- a/NHSISL.LibPostalClient.Tests.Acceptance/NHSISL - Backup.LibPostalClient.Tests.Acceptance.csproj +++ b/NHSISL.LibPostalClient.Tests.Acceptance/NHSISL - Backup.LibPostalClient.Tests.Acceptance.csproj @@ -1,7 +1,7 @@  - net7.0 + net10.0 disable enable false diff --git a/NHSISL.LibPostalClient.Tests.Acceptance/NHSISL.LibPostalClient.Tests.Acceptance.csproj b/NHSISL.LibPostalClient.Tests.Acceptance/NHSISL.LibPostalClient.Tests.Acceptance.csproj index c2a4165..d32aa1d 100644 --- a/NHSISL.LibPostalClient.Tests.Acceptance/NHSISL.LibPostalClient.Tests.Acceptance.csproj +++ b/NHSISL.LibPostalClient.Tests.Acceptance/NHSISL.LibPostalClient.Tests.Acceptance.csproj @@ -23,7 +23,11 @@ - + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/NHSISL.LibPostalClient.Tests.Unit/NHSISL - Backup.LibPostalClient.Tests.Unit.csproj b/NHSISL.LibPostalClient.Tests.Unit/NHSISL - Backup.LibPostalClient.Tests.Unit.csproj index af8c500..2f893f1 100644 --- a/NHSISL.LibPostalClient.Tests.Unit/NHSISL - Backup.LibPostalClient.Tests.Unit.csproj +++ b/NHSISL.LibPostalClient.Tests.Unit/NHSISL - Backup.LibPostalClient.Tests.Unit.csproj @@ -1,7 +1,7 @@  - net7.0 + net10.0 disable enable false @@ -12,7 +12,7 @@ - + diff --git a/NHSISL.LibPostalClient.Tests.Unit/NHSISL.LibPostalClient.Tests.Unit.csproj b/NHSISL.LibPostalClient.Tests.Unit/NHSISL.LibPostalClient.Tests.Unit.csproj index 48591ef..12b992e 100644 --- a/NHSISL.LibPostalClient.Tests.Unit/NHSISL.LibPostalClient.Tests.Unit.csproj +++ b/NHSISL.LibPostalClient.Tests.Unit/NHSISL.LibPostalClient.Tests.Unit.csproj @@ -18,7 +18,11 @@ - + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/NHSISL.LibPostalNet/NHSISL.LibPostalNet.csproj b/NHSISL.LibPostalNet/NHSISL.LibPostalNet.csproj index e4fec4f..535130f 100644 --- a/NHSISL.LibPostalNet/NHSISL.LibPostalNet.csproj +++ b/NHSISL.LibPostalNet/NHSISL.LibPostalNet.csproj @@ -1,6 +1,6 @@  - netstandard2.1 + net10.0 Library false true