diff --git a/.github/internal-cicd/scripts/deno-check.ts b/.github/internal-cicd/scripts/deno-check.ts deleted file mode 100644 index 53c0ca09..00000000 --- a/.github/internal-cicd/scripts/deno-check.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { Directory, CLI } from "../../../deps.ts"; - -const ignoreDirectories = [ - "./vendor/", - "./node_modules/" -]; - -const files: string[] = Directory - .getFiles("/", true) - .filter(f => { - const isTypeScriptFile = f.endsWith(".ts"); - - const shouldNotIgnore = ignoreDirectories.every(ignoreDir => !f.startsWith(ignoreDir)) - - return isTypeScriptFile && shouldNotIgnore; - }); - -const cli: CLI = new CLI(); -let failed = false; - -console.clear(); -console.log(`Checking ${files.length} files . . .`); - -/** - * Represents the result of checking a file. - */ -interface CheckResult { - file: string; - result: string; - hasPassed: boolean; -} - -/** - * Checks a file using deno check. - * @param file The file to check. - * @returns A promise that resolves to a CheckResult. - */ -const checkFile = async (file: string): Promise => { - let checkResult: CheckResult = { - file: file, - result: "", - hasPassed: true // Default to passed - }; - - checkResult.result += `Checking ${file}`; - - const result = await cli.runAsync(`deno check ${file}`); - - let commandResult = ""; - - // If the result is an error type - if (result instanceof Error) - { - checkResult.hasPassed = false; - commandResult = "❌\n"; - - const lines = result.message.split("\n"); - - // Prefix each command output line with 3 spaces - lines.forEach(line => { - commandResult += ` ${line}\n`; - }); - } else { - commandResult = "✅\n"; - } - - checkResult.result += commandResult; - - return checkResult; -} - -const filesToCheck: Promise[] = []; - -// Perform a deno check on all of the files -for await (let file of files) { - filesToCheck.push(checkFile(file)); -}; - -// Wait for all of the checks to complete -const allCheckResults = await Promise.all(filesToCheck); - -// Print all of the results -allCheckResults.forEach(checkResult => { - Deno.stdout.writeSync(new TextEncoder().encode(checkResult.result)); -}); - -// Collect the total number of passed and failed checks -const totalPassed = allCheckResults.filter(r => r.hasPassed).length; -const totalFailed = allCheckResults.filter(r => !r.hasPassed).length; - -const resultsMsg = new TextEncoder().encode(`\nTotal Checks Passed✅: ${totalPassed}\nTotal Checks Failed❌: ${totalFailed}\n`); -Deno.stdout.writeSync(resultsMsg); - -if (failed) { - Deno.exit(1); -} diff --git a/.github/internal-cicd/scripts/get-validate-version.ts b/.github/internal-cicd/scripts/get-validate-version.ts new file mode 100644 index 00000000..212a8f32 --- /dev/null +++ b/.github/internal-cicd/scripts/get-validate-version.ts @@ -0,0 +1,35 @@ +import getEnvVar from "../../../cicd/core/GetEnvVar.ts"; +import { Utils } from "../../../cicd/core/Utils.ts"; +import DenoConfig from "../../../deno.json" with { type: "json" }; + +const scriptFileName = new URL(import.meta.url).pathname.split("/").pop(); + +if (Utils.isNothing(DenoConfig.version)) { + Utils.printAsGitHubError(`The Deno version is not defined in the deno.json file.\n${scriptFileName}`); + Deno.exit(1); +} + +const githubOutputFilePath = getEnvVar("GITHUB_OUTPUT", scriptFileName); + +const version = (DenoConfig.version.startsWith("v") + ? DenoConfig.version.trim().toLocaleLowerCase() + : `v${DenoConfig.version}`).trim().toLocaleLowerCase(); + +const versionRegex = /^v([1-9]\d*|0)\.([1-9]\d*|0)\.([1-9]\d*|0)(-preview\.([1-9]\d*))?$/gm; + +if (!versionRegex.test(version)) { + Utils.printAsGitHubError(`The version '${version}' is not valid.\n\t\n${scriptFileName}`); + Deno.exit(1); +} + +try { + Deno.writeTextFileSync(githubOutputFilePath, `version=${version}\n`, { append: true }); +} catch (error) { + if (error instanceof Error) { + Utils.printAsGitHubError(`${error.message}\n${scriptFileName}`); + } else { + Utils.printAsGitHubError(`An unknown error occurred.\n${scriptFileName}`); + } + + Deno.exit(1); +} diff --git a/.github/internal-cicd/scripts/update-csharp-proj.ts b/.github/internal-cicd/scripts/update-csharp-proj.ts index 45a5349b..a010a6c3 100644 --- a/.github/internal-cicd/scripts/update-csharp-proj.ts +++ b/.github/internal-cicd/scripts/update-csharp-proj.ts @@ -10,4 +10,3 @@ const token = getEnvVar("GITHUB_TOKEN", scriptFileName); const service = new CSharpVersionService("KinsonDigital", "Infrastructure", token); await service.updateVersion(version, ReleaseType.preview); - diff --git a/.github/internal-cicd/scripts/update-workflow-versions.ts b/.github/internal-cicd/scripts/update-workflow-versions.ts index e26d4fa2..3b9c33c2 100644 --- a/.github/internal-cicd/scripts/update-workflow-versions.ts +++ b/.github/internal-cicd/scripts/update-workflow-versions.ts @@ -1,6 +1,4 @@ -import { - TagClient, RepoClient, Directory, Input -} from "../../../deps.ts"; +import { Directory, Input, RepoClient, TagClient } from "../../../deps.ts"; import chalk from "../../../deps.ts"; import { File } from "../../../cicd/core/File.ts"; import { Utils } from "../../../cicd/core/Utils.ts"; @@ -34,7 +32,7 @@ const newVersion = await Input.prompt({ value = value.trim().toLowerCase(); return value.startsWith("v") ? value : `v${value}`; - } + }, }); const ownerName = "KinsonDigital"; @@ -58,15 +56,15 @@ const updateMsgs: string[] = []; let noFilesUpdated = true; // Search for workflow references with a version that has not been updated -yamlFiles.forEach(yamlFile => { +yamlFiles.forEach((yamlFile) => { let fileContent = File.LoadFile(yamlFile); const possibleUpdates = fileContent.match(reusableWorkflowRegex)?.map((w) => w) ?? []; let fileUpdated = false; - // Check each reusable workflow reference version - possibleUpdates.forEach(oldRef => { + // Check each reusable workflow reference version + possibleUpdates.forEach((oldRef) => { const refPathSection = oldRef.split("uses:")[1].trim().split("@")[0]; const workflowRefVersion = oldRef.split("@")[1]; @@ -79,7 +77,8 @@ yamlFiles.forEach(yamlFile => { // Update the reusable workflow reference version fileContent = fileContent.replaceAll(oldRef, newRef); - const noticeMsg = `Updated reusable workflow reference '${refPathSection}' from version '${workflowRefVersion}' to '${newVersion}'.`; + const noticeMsg = + `Updated reusable workflow reference '${refPathSection}' from version '${workflowRefVersion}' to '${newVersion}'.`; updateMsgs.push(noticeMsg); } }); @@ -96,7 +95,7 @@ if (noFilesUpdated) { console.log(chalk.cyan("No files needed updating.")); } else { updateMsgs.sort(); - updateMsgs.forEach(updateMsg => { + updateMsgs.forEach((updateMsg) => { console.log(chalk.cyan(updateMsg)); }); } @@ -113,4 +112,6 @@ const scriptVersionVar = (await repoClient.getVariables()).find((v) => v.name == await repoClient.updateVariable(repoVarName, newVersion); -console.log(chalk.cyan(`Updated repository variable '${repoVarName}' from version '${scriptVersionVar?.value}' to '${newVersion}'.`)); +console.log( + chalk.cyan(`Updated repository variable '${repoVarName}' from version '${scriptVersionVar?.value}' to '${newVersion}'.`), +); diff --git a/.github/internal-cicd/scripts/workflow-version-status-check.ts b/.github/internal-cicd/scripts/workflow-version-status-check.ts index 3a476681..5c94c7eb 100644 --- a/.github/internal-cicd/scripts/workflow-version-status-check.ts +++ b/.github/internal-cicd/scripts/workflow-version-status-check.ts @@ -1,100 +1 @@ -import { walkSync } from "@std/fs/walk"; -import { exists } from "@std/fs/exists"; -import { basename } from "@std/path/basename"; -import { TagClient } from "../../../deps.ts"; -import { Utils } from "../../../cicd/core/Utils.ts"; -import getEnvVar from "../../../cicd/core/GetEnvVar.ts"; -import { validateOrgExists, validateRepoExists } from "../../../cicd/core/Validators.ts"; - -const scriptFileName = new URL(import.meta.url).pathname.split("/").pop(); - -const ownerName = getEnvVar("OWNER_NAME", scriptFileName); -const repoName = getEnvVar("REPO_NAME", scriptFileName); -let baseDirPath = getEnvVar("BASE_DIR_PATH", scriptFileName); -baseDirPath = Utils.normalizePath(baseDirPath); -const token = getEnvVar("GITHUB_TOKEN", scriptFileName); - -await validateOrgExists(scriptFileName); -await validateRepoExists(scriptFileName); - -if (!exists(baseDirPath)) { - Utils.printAsGitHubError(`Directory '${baseDirPath}' does not exist.`); - Deno.exit(1); -} - -const yamlFiles = [...walkSync(baseDirPath, { - includeDirs: false, - includeFiles: true, - exts: [".yaml", ".yml"], -})].map((e) => e.path); - -const tagClient: TagClient = new TagClient(ownerName, repoName, token); - -const existingReleaseTags = (await tagClient.getAllTags()).map((t) => t.name); - -const workflowsToUpdate: WorkflowToUpdate[] = []; - -const reusableWorkflowRegex = /uses: .+.(yml|yaml)@v([1-9]\d*|0)\.([1-9]\d*|0)\.([1-9]\d*|0)(-preview\.([1-9]\d*))?/gm; - -type WorkflowToUpdate = { - /** - * The file path to the workflow. - */ - filePath: string; - - /** - * The reusable workflow references that need to be updated. - */ - workflowRefs: string[]; -}; - -// Search for workflow references with a version that has not been updated -yamlFiles.forEach(yamlFile => { - const workflowToUpdate: WorkflowToUpdate = { - filePath: yamlFile, - workflowRefs: [] - }; - - const fileContent = Deno.readTextFileSync(yamlFile); - - const possibleUpdates = fileContent.match(reusableWorkflowRegex)?.map((w) => w) ?? []; - - // Check each reusable workflow reference version - possibleUpdates.forEach(possibleUpdate => { - const fullRef = possibleUpdate.split("uses:")[1].trim(); - const workflowRefVersion = possibleUpdate.split("@")[1]; - - // If the workflow version has not been updated - if (existingReleaseTags.includes(workflowRefVersion)) { - workflowToUpdate.workflowRefs.push(fullRef); - } - }); - - if (workflowToUpdate.workflowRefs.length > 0) { - workflowsToUpdate.push(workflowToUpdate); - } -}); - -// If there are no workflows to update, then exit -if (workflowsToUpdate.length === 0) { - Utils.printAsGitHubNotice("No workflows to update."); - Deno.exit(0); -} - -const errorMsgs: string[] = []; - -// Print out all of the workflows that need to be updated as an error -workflowsToUpdate.forEach(workflowToUpdate => { - const filePath = basename(workflowToUpdate.filePath); - - const workflowErrors: string[] = workflowToUpdate.workflowRefs.map((workflowRef) => { - return `Workflow reference '${workflowRef}' in file '${filePath}' needs to be updated.`; - }); - - errorMsgs.push(...workflowErrors); -}); - -if (errorMsgs.length > 0) { - Utils.printAsGitHubErrors(errorMsgs); - Deno.exit(1); -} +import "../../../cicd/scripts/check-workflow-versions.ts"; diff --git a/.github/workflows/add-item-to-project.yml b/.github/workflows/add-item-to-project.yml index c0e77614..69ccc239 100644 --- a/.github/workflows/add-item-to-project.yml +++ b/.github/workflows/add-item-to-project.yml @@ -62,7 +62,7 @@ jobs: } - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/add-new-item-to-project.yml b/.github/workflows/add-new-item-to-project.yml index 707edb8b..47cc7ba5 100644 --- a/.github/workflows/add-new-item-to-project.yml +++ b/.github/workflows/add-new-item-to-project.yml @@ -36,7 +36,7 @@ jobs: add_new_item_to_project: name: Add New Issue needs: item_number - uses: KinsonDigital/Infrastructure/.github/workflows/add-item-to-project.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/add-item-to-project.yml@v14.0.0 with: org-name: "${{ vars.ORGANIZATION_NAME }}" org-project-name: "${{ vars.ORG_PROJECT_NAME }}" diff --git a/.github/workflows/build-csharp-project.yml b/.github/workflows/build-csharp-project.yml index 3f574663..1dd3785a 100644 --- a/.github/workflows/build-csharp-project.yml +++ b/.github/workflows/build-csharp-project.yml @@ -90,7 +90,7 @@ jobs: resolve_proj_file_path: name: Resolving ${{ inputs.project-name }} Project File Path needs: print_validate_workflow - uses: KinsonDigital/Infrastructure/.github/workflows/resolve-csharp-proj-file.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/resolve-csharp-proj-file.yml@v14.0.0 with: project-name: ${{ inputs.project-name }} base-path: ${{ inputs.base-path }} diff --git a/.github/workflows/build-status-check.yml b/.github/workflows/build-status-check.yml index 87162e34..56a61bc5 100644 --- a/.github/workflows/build-status-check.yml +++ b/.github/workflows/build-status-check.yml @@ -23,11 +23,10 @@ jobs: repository: ${{ github.event.pull_request.head.repo.full_name }} ref: ${{ github.event.pull_request.head.ref }} - - name: Setup Deno - uses: denoland/setup-deno@v1 + - name: Setup Deno (${{ vars.DENO_VERSION }}) + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} - - name: Run Build - run: | - deno run --allow-read --allow-run --allow-sys "./.github/internal-cicd/scripts/deno-check.ts"; + - name: Run Check + run: deno check ./**/*.ts; diff --git a/.github/workflows/dotnet-action-release.yml b/.github/workflows/dotnet-action-release.yml index 461b21fa..667fd73c 100644 --- a/.github/workflows/dotnet-action-release.yml +++ b/.github/workflows/dotnet-action-release.yml @@ -157,7 +157,7 @@ jobs: validate_version: name: Validate Version needs: [print_validate_workflow, validate_branch] - uses: KinsonDigital/Infrastructure/.github/workflows/validate-csharp-version.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/validate-csharp-version.yml@v14.0.0 with: project-name: "${{ inputs.project-name }}" release-type: "${{ inputs.release-type }}" @@ -168,7 +168,7 @@ jobs: validate_tag: name: Validate Tag needs: validate_version - uses: KinsonDigital/Infrastructure/.github/workflows/validate-tag.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/validate-tag.yml@v14.0.0 with: project-name: "${{ inputs.project-name }}" release-type: "${{ inputs.release-type }}" @@ -180,7 +180,7 @@ jobs: validate_sdk_setup: name: Validate SDK Setup needs: print_validate_workflow - uses: KinsonDigital/Infrastructure/.github/workflows/validate-sdk-versions.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/validate-sdk-versions.yml@v14.0.0 with: repo-name: "${{ inputs.project-name }}" secrets: @@ -216,7 +216,7 @@ jobs: validate_github_release: name: GitHub Release Does Not Exist needs: validate_version - uses: KinsonDigital/Infrastructure/.github/workflows/validate-github-release.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/validate-github-release.yml@v14.0.0 with: project-name: "${{ inputs.project-name }}" version: "${{ needs.validate_version.outputs.version }}" @@ -227,7 +227,7 @@ jobs: build_project: name: Build Main Project (${{ inputs.project-name }}) needs: print_validate_workflow - uses: KinsonDigital/Infrastructure/.github/workflows/build-csharp-project.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/build-csharp-project.yml@v14.0.0 with: project-name: "${{ inputs.project-name }}" runs-on: "${{ inputs.runs-on }}" @@ -240,7 +240,7 @@ jobs: run_tests: name: Run Tests needs: print_validate_workflow - uses: KinsonDigital/Infrastructure/.github/workflows/run-csharp-tests.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/run-csharp-tests.yml@v14.0.0 with: project-name: "${{ inputs.project-name }}Tests" runs-on: "${{ inputs.runs-on }}" diff --git a/.github/workflows/dotnet-lib-release.yml b/.github/workflows/dotnet-lib-release.yml index f903a0e4..520861f1 100644 --- a/.github/workflows/dotnet-lib-release.yml +++ b/.github/workflows/dotnet-lib-release.yml @@ -93,7 +93,7 @@ env: jobs: validate_version: name: Validate Version - uses: KinsonDigital/Infrastructure/.github/workflows/validate-csharp-version.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/validate-csharp-version.yml@v14.0.0 with: project-name: "${{ inputs.project-name }}" release-type: "${{ inputs.release-type }}" @@ -107,7 +107,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} @@ -138,8 +138,6 @@ jobs: id: tag-check continue-on-error: true env: - OWNER_NAME: "${{ vars.ORGANIZATION_NAME }}" - REPO_NAME: "${{ inputs.project-name }}" RELEASE_TYPE: "${{ inputs.release-type }}" TAG_NAME: "${{ needs.validate_version.outputs.version }}" GITHUB_TOKEN: "${{ secrets.cicd-pat }}" @@ -186,8 +184,6 @@ jobs: - name: Validate Milestone id: milestone-check env: - OWNER_NAME: "${{ vars.ORGANIZATION_NAME }}" - REPO_NAME: "${{ inputs.project-name }}" MILESTONE_TITLE: "${{ needs.validate_version.outputs.version }}" GITHUB_TOKEN: "${{ secrets.cicd-pat }}" continue-on-error: true @@ -200,8 +196,6 @@ jobs: id: github-release-check continue-on-error: true env: - OWNER_NAME: "${{ vars.ORGANIZATION_NAME }}" - REPO_NAME: "${{ inputs.project-name }}" TAG_NAME: "${{ needs.validate_version.outputs.version }}" GITHUB_TOKEN: "${{ secrets.cicd-pat }}" run: | @@ -263,7 +257,7 @@ jobs: build_project: name: Build Main Project needs: [run_prerelease_validation] - uses: KinsonDigital/Infrastructure/.github/workflows/build-csharp-project.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/build-csharp-project.yml@v14.0.0 with: project-name: "${{ inputs.project-name }}" runs-on: "${{ inputs.runs-on }}" @@ -276,7 +270,7 @@ jobs: run_tests: name: Run Tests needs: [run_prerelease_validation] - uses: KinsonDigital/Infrastructure/.github/workflows/run-csharp-tests.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/run-csharp-tests.yml@v14.0.0 with: project-name: "${{ inputs.project-name }}Tests" runs-on: "${{ inputs.runs-on }}" @@ -304,7 +298,7 @@ jobs: uses: NuGet/setup-nuget@v1 - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/initial-manual-sync.yml b/.github/workflows/initial-manual-sync.yml index b27dae87..ab997646 100644 --- a/.github/workflows/initial-manual-sync.yml +++ b/.github/workflows/initial-manual-sync.yml @@ -80,7 +80,7 @@ jobs: - name: Set Up Deno if: ${{ steps.skip-checking.outputs.skip == 'false' }} - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/lint-status-check.yml b/.github/workflows/lint-status-check.yml index 78a75874..39d3b983 100644 --- a/.github/workflows/lint-status-check.yml +++ b/.github/workflows/lint-status-check.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@v4 - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/nuget-package-does-not-exist.yml b/.github/workflows/nuget-package-does-not-exist.yml index 3dba1eb1..f312ef44 100644 --- a/.github/workflows/nuget-package-does-not-exist.yml +++ b/.github/workflows/nuget-package-does-not-exist.yml @@ -53,7 +53,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..77532635 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,265 @@ +name: 🚀Release +run-name: 🚀${{ inputs.release-type }} Release ${{ inputs.dry-run == true && '(Dry Run)' || '' }} + + +defaults: + run: + shell: pwsh + + +on: + workflow_dispatch: + inputs: + release-type: + required: true + description: The type of release to validate. Either 'Preview' or 'Production'. + type: choice + options: [Production, Preview] + dry-run: + required: false + description: If true, the release will not be created. + default: false + type: boolean + + +env: + OWNER_NAME: "${{ vars.ORGANIZATION_NAME }}" + REPO_NAME: "${{ vars.PROJECT_NAME }}" + + +jobs: + get_validate_version: + name: Get & Validate Version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.get-version.outputs.version }} + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Set Up Deno (${{ vars.DENO_VERSION }}) + uses: denoland/setup-deno@v2 + with: + deno-version: ${{ vars.DENO_VERSION }} + + - name: Get & Validate Version + id: get-version + run: deno -ERW ".github/internal-cicd/scripts/get-validate-version.ts"; + + + run_prerelease_validation: + name: Run Pre-Release Validation + needs: [get_validate_version] + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Set Up Deno + uses: denoland/setup-deno@v2 + with: + deno-version: ${{ vars.DENO_VERSION }} + + - name: Build Script Base URL + id: build-script-base-url + run: | + # Construct the URL to the organizations CICD scripts + $scriptUrl = "${{ vars.SCRIPT_BASE_URL }}/${{ vars.CICD_SCRIPTS_VERSION }}/${{ vars.SCRIPT_RELATIVE_DIR_PATH }}"; + $scriptUrl = $scriptUrl.Replace("\", "/").Replace("//", "/"); + $scriptUrl = $scriptUrl.EndsWith("/") ? $scriptUrl.Substring(0, $scriptUrl.Length - 1) : $scriptUrl; + + Write-Host "::notice::Script Base URL: $scriptUrl"; + + "url=$scriptUrl" >> $env:GITHUB_OUTPUT; + + - name: Branch Check + id: branch-check + continue-on-error: true + run: | + if ("${{ github.ref_name }}" -ne "main") { + Write-Host "::error::The branch '$branch' is invalid. Please only run on the 'main' branch."; + exit 1; + } + + - name: Milestone Exists + id: milestone-exists-check + continue-on-error: true + env: + MILESTONE_TITLE: "${{ needs.get_validate_version.outputs.version }}" + GITHUB_TOKEN: ${{ secrets.CICD_TOKEN }} + run: | + $scriptUrl = "${{ steps.build-script-base-url.outputs.url }}/milestone-exists.ts"; + + deno run -ERNS "$scriptUrl"; + + - name: Validate Milestone + id: milestone-check + env: + MILESTONE_TITLE: "${{ needs.get_validate_version.outputs.version }}" + GITHUB_TOKEN: "${{ secrets.CICD_TOKEN }}" + continue-on-error: true + run: | + $scriptUrl = "${{ steps.build-script-base-url.outputs.url }}/milestone-items-all-closed.ts"; + + deno run -ERN "$scriptUrl"; + + - name: Release Notes Does Not Exist + id: release-notes-check + continue-on-error: true + env: + RELEASE_NOTES_DIR_PATH: "${{ github.workspace }}/ReleaseNotes/${{ inputs.release-type }}Releases" + VERSION: "${{ needs.get_validate_version.outputs.version }}" + run: | + $scriptUrl = "${{ steps.build-script-base-url.outputs.url }}/release-notes-do-not-exist.ts"; + + Write-Host "::notice::Validate Release Notes Exist Script URL: $scriptUrl"; + + deno run -ER "$scriptUrl"; + + - name: GitHub Release Does Not Exist + id: github-release-check + continue-on-error: true + env: + TAG_NAME: "${{ needs.get_validate_version.outputs.version }}" + GITHUB_TOKEN: "${{ secrets.CICD_TOKEN }}" + run: | + $scriptUrl = "${{ steps.build-script-base-url.outputs.url }}/github-release-does-not-exist.ts"; + + Write-Host "::notice::Validate GitHub Release Version Script URL: $scriptUrl"; + + deno run -ERN "$scriptUrl"; + + - name: Check Reusable Workflow Versions + id: workflow-versions-check + continue-on-error: true + env: + BASE_DIR_PATH: "${{ github.workspace }}/.github/workflows" + GITHUB_TOKEN: "${{ secrets.CICD_TOKEN }}" + run: deno run -ERN "${{ steps.build-script-base-url.outputs.url }}/check-workflow-versions.ts"; + + - name: Should Fail Job + run: | + $branchCheckFailed = "${{ steps.branch-check.outcome == 'failure' }}"; + $milestoneExistsCheckFailed = "${{ steps.milestone-exists-check.outcome == 'failure' }}"; + $milestoneCheckFailed = "${{ steps.milestone-check.outcome == 'failure' }}"; + $releaseNotesCheckFailed = "${{ steps.release-notes-check.outcome == 'failure' }}"; + $githubReleaseCheckFailed = "${{ steps.github-release-check.outcome == 'failure' }}"; + $workflowVersionsCheckCheckFailed = "${{ steps.workflow-versions-check.outcome == 'failure' }}"; + + if ($branchCheckFailed -eq "true") { + Write-Host "::error::The branch is invalid. Check the 'run-branch' workflow input."; + } + + if ($milestoneExistsCheckFailed -eq "true") { + Write-Host "::error::The milestone '${{ needs.get_validate_version.outputs.version }}' does not exist."; + } + + if ($milestoneCheckFailed -eq "true") { + Write-Host "::error::The milestone '${{ needs.get_validate_version.outputs.version }}' has one or more issues that are not closed."; + } + + if ($releaseNotesCheckFailed -eq "true") { + Write-Host "::error::The release notes do not exist."; + } + + if ($githubReleaseCheckFailed -eq "true") { + Write-Host "::error::The GitHub release already exists."; + } + + if ($workflowVersionsCheckCheckFailed -eq "true") { + Write-Host "::error::The one or more reusable workflow versions haver not been updated."; + } + + if ($branchCheckFailed -eq "true" ` + -or $milestoneExistsCheckFailed -eq "true" ` + -or $milestoneCheckFailed -eq "true" ` + -or $releaseNotesCheckFailed -eq "true" ` + -or $githubReleaseCheckFailed -eq "true" ` + -or $workflowVersionsCheckCheckFailed -eq "true") { + exit 1; + } + + + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Setup Deno (${{ vars.DENO_VERSION }}) + uses: denoland/setup-deno@v2 + with: + deno-version: ${{ vars.DENO_VERSION }} + + - name: Build + run: deno check ./**/*.ts; + + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Setup Deno (${{ vars.DENO_VERSION }}) + uses: denoland/setup-deno@v2 + with: + deno-version: ${{ vars.DENO_VERSION }} + + - name: Lint + run: | + $tsFiles = Get-ChildItem -Path ${{ github.workspace }} -Recurse -Filter *.ts | ForEach-Object { $_.FullName }; + $tsFiles -join "`n"; + + deno lint "./**/*.ts"; + + + perform_release: + name: Perform ${{ inputs.release-type }} Release + runs-on: ubuntu-latest + needs: [get_validate_version, run_prerelease_validation, build, lint] + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Set Up Deno + uses: denoland/setup-deno@v2 + with: + deno-version: ${{ vars.DENO_VERSION }} + + - name: Create Script URL + id: script-url + run: | + # Construct the URL to the organizations CICD scripts + $url = "${{ vars.SCRIPT_BASE_URL }}/${{ vars.CICD_SCRIPTS_VERSION }}/${{ vars.SCRIPT_RELATIVE_DIR_PATH }}"; + $url = $url.Replace("\", "/").Replace("//", "/"); + $url = $url.EndsWith("/") ? $url.Substring(0, $url.Length - 1) : $url; + + Write-Host "::notice::DotNet Lib Release Script URL: $url"; + "url=$url" >> "$env:GITHUB_OUTPUT"; + + - name: Create GitHub Release ${{ inputs.dry-run == true && '(Dry Run)' || '' }} + if: ${{ inputs.dry-run == false }} + uses: ncipollo/release-action@v1 + with: + name: "🚀${{ inputs.release-type }} - ${{ needs.get_validate_version.outputs.version }}" + tag: ${{ needs.get_validate_version.outputs.version }} + owner: ${{ env.OWNER_NAME }} + repo: ${{ env.REPO_NAME }} + bodyFile: "${{ github.workspace }}/ReleaseNotes/${{ inputs.release-type }}Releases/Release-Notes-${{ needs.get_validate_version.outputs.version }}.md" + artifacts: "${{ github.workspace }}/ReleaseNotes/${{ inputs.release-type }}Releases/Release-Notes-${{ needs.get_validate_version.outputs.version }}.md" + prerelease: ${{ inputs.release-type }} == 'Preview' + + - name: Close Milestone ${{ inputs.dry-run == true && '(Dry Run)' || '' }} + env: + MILESTONE_NAME: "${{ needs.get_validate_version.outputs.version }}" + GITHUB_TOKEN: "${{ secrets.CICD_TOKEN }}" + run: | + if ("${{ inputs.dry-run == true }}" -eq "true") { + Write-Host "::notice::Dry Run: Closing milestone..."; + exit 0; + } + + deno run -ERN "${{ steps.script-url.outputs.url }}/close-milestone.ts"; diff --git a/.github/workflows/resolve-csharp-proj-file.yml b/.github/workflows/resolve-csharp-proj-file.yml index fc22a7d6..e53c2fb4 100644 --- a/.github/workflows/resolve-csharp-proj-file.yml +++ b/.github/workflows/resolve-csharp-proj-file.yml @@ -37,7 +37,7 @@ jobs: - uses: actions/checkout@v4 - name: Set Up Deno (${{ vars.DENO_VERSION }}) - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/run-csharp-tests.yml b/.github/workflows/run-csharp-tests.yml index 750fc768..74b91f38 100644 --- a/.github/workflows/run-csharp-tests.yml +++ b/.github/workflows/run-csharp-tests.yml @@ -92,7 +92,7 @@ jobs: resolve_proj_file_path: name: Resolving ${{ inputs.project-name }} Project File Path needs: print_validate_workflow - uses: KinsonDigital/Infrastructure/.github/workflows/resolve-csharp-proj-file.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/resolve-csharp-proj-file.yml@v14.0.0 with: project-name: ${{ inputs.project-name }} base-path: ${{ inputs.base-path }} diff --git a/.github/workflows/sync-bot.yml b/.github/workflows/sync-bot.yml index eb8056a8..fe7b0c56 100644 --- a/.github/workflows/sync-bot.yml +++ b/.github/workflows/sync-bot.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/sync-pr-to-issue.yml b/.github/workflows/sync-pr-to-issue.yml index 85e0a580..49961f78 100644 --- a/.github/workflows/sync-pr-to-issue.yml +++ b/.github/workflows/sync-pr-to-issue.yml @@ -20,7 +20,7 @@ jobs: github.event_name == 'pull_request_target' && !startsWith(github.head_ref, 'renovate/') && github.head_ref != 'prev-release' && github.head_ref != 'prod-release' - uses: KinsonDigital/Infrastructure/.github/workflows/initial-manual-sync.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/initial-manual-sync.yml@v14.0.0 with: issue-or-pr-number: ${{ github.event.pull_request.number }} sync-type: initial @@ -37,7 +37,7 @@ jobs: github.head_ref != 'prev-release' && github.head_ref != 'prod-release' && github.event.issue.pull_request && github.event.issue.pull_request.url != null && contains(github.event.comment.body, '[run-sync]') - uses: KinsonDigital/Infrastructure/.github/workflows/initial-manual-sync.yml@v13.6.3 + uses: KinsonDigital/Infrastructure/.github/workflows/initial-manual-sync.yml@v14.0.0 with: issue-or-pr-number: ${{ github.event.issue.number }} sync-type: manual diff --git a/.github/workflows/validate-csharp-version.yml b/.github/workflows/validate-csharp-version.yml index a6b624f0..52bd9508 100644 --- a/.github/workflows/validate-csharp-version.yml +++ b/.github/workflows/validate-csharp-version.yml @@ -73,7 +73,7 @@ jobs: version-keys: Version - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/validate-github-release.yml b/.github/workflows/validate-github-release.yml index 048f9a75..c9786eab 100644 --- a/.github/workflows/validate-github-release.yml +++ b/.github/workflows/validate-github-release.yml @@ -66,7 +66,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/validate-milestone-status.yml b/.github/workflows/validate-milestone-status.yml index 1ba6a992..fd8caeb4 100644 --- a/.github/workflows/validate-milestone-status.yml +++ b/.github/workflows/validate-milestone-status.yml @@ -69,7 +69,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/validate-sdk-versions.yml b/.github/workflows/validate-sdk-versions.yml index c8f41de8..1ce99234 100644 --- a/.github/workflows/validate-sdk-versions.yml +++ b/.github/workflows/validate-sdk-versions.yml @@ -40,7 +40,7 @@ jobs: } - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/validate-tag.yml b/.github/workflows/validate-tag.yml index 345419e5..690c14e9 100644 --- a/.github/workflows/validate-tag.yml +++ b/.github/workflows/validate-tag.yml @@ -78,7 +78,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.github/workflows/workflow-version-status-check.yml b/.github/workflows/workflow-version-status-check.yml index f09a0142..0acb57a3 100644 --- a/.github/workflows/workflow-version-status-check.yml +++ b/.github/workflows/workflow-version-status-check.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@v4 - name: Set Up Deno - uses: denoland/setup-deno@v1 + uses: denoland/setup-deno@v2 with: deno-version: ${{ vars.DENO_VERSION }} diff --git a/.gitignore b/.gitignore index 634563b2..0ccea13d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ **/obj **/cicd/**/bin *.sln + +# Ignore file used for testing the GitHub environment output file +/github_output.txt diff --git a/.vscode/launch.json b/.vscode/launch.json index c822c3cc..51a66f64 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -540,45 +540,67 @@ "runtimeExecutable": "${userHome}/.deno/bin/deno" } }, - { // BUILD (DENO CHECK) - "name": "Build (Deno Check)", + { // VALIDATE SDK VERSIONS + "name": "Validate SDK Versions", "request": "launch", "type": "node", - "program": "${workspaceFolder}/.github/internal-cicd/scripts/deno-check.ts", - "cwd": "${workspaceFolder}", + "program": "${workspaceFolder}/cicd/scripts/validate-sdk-versions.ts", + "cwd": "${workspaceFolder}", "runtimeArgs": [ "run", + "-ER", "--inspect-wait", - "--allow-read", - "--allow-run", ], + "env": { + "BASE_SEARCH_DIR_PATH": "${workspaceFolder}", + "NET_SDK_VERSION": "7.0", + }, "attachSimplePort": 9229, - "runtimeExecutable": "npm", - "outputCapture": "std", - "skipFiles": [ - "/**" - ], "windows": { "runtimeExecutable": "${userHome}/.deno/bin/deno.exe" }, "linux": { "runtimeExecutable": "${userHome}/.deno/bin/deno" + } + }, + { // GET VALIDATE VERSION + "name": "Get Validate Version", + "request": "launch", + "type": "node", + "program": "${workspaceFolder}/.github/internal-cicd/scripts/get-validate-version.ts", + "cwd": "${workspaceFolder}", + "runtimeArgs": [ + "run", + "-ERW", + "--inspect-wait", + ], + "env": { + "GITHUB_OUTPUT": "${workspaceFolder}/github_output.txt", + }, + "attachSimplePort": 9229, + "windows": { + "runtimeExecutable": "${userHome}/.deno/bin/deno.exe" }, - }, - { // VALIDATE SDK Versions - "name": "Validate SDK Versions", + "linux": { + "runtimeExecutable": "${userHome}/.deno/bin/deno" + } + }, + { // CHECK WORKFLOW VERSIONS + "name": "Check Workflow Versions", "request": "launch", "type": "node", - "program": "${workspaceFolder}/cicd/scripts/validate-sdk-versions.ts", + "program": "${workspaceFolder}/cicd/scripts/check-workflow-versions.ts", "cwd": "${workspaceFolder}", "runtimeArgs": [ "run", - "-ER", + "-ERN", "--inspect-wait", ], "env": { - "BASE_SEARCH_DIR_PATH": "${workspaceFolder}", - "NET_SDK_VERSION": "7.0", + "OWNER_NAME": "KinsonDigital", + "REPO_NAME": "Infrastructure", + "BASE_DIR_PATH": "${workspaceFolder}/.github/workflows", + "GITHUB_TOKEN": "${env:CICD_TOKEN}", }, "attachSimplePort": 9229, "windows": { diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 213c3464..1b6af88d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -47,27 +47,6 @@ "${workspaceFolder}/.github/internal-cicd/scripts/update-workflow-versions.ts", ] } - }, - { // BUILD (DENO CHECK) - "label": "Build (Deno Check)", - "detail": "Builds the project using deno check.", - "command": "deno", - "dependsOn": ["clear-terminal"], - "type": "shell", - "args": [ - "run", - "--allow-read", - "--allow-run", - "--allow-sys", - "${workspaceFolder}/.github/internal-cicd/scripts/deno-check.ts" - ], - "problemMatcher": [ - "$tsc" - ], - "presentation": { - "reveal": "always" - }, - "group": "build" } ] } diff --git a/cicd/core/GetEnvVar.ts b/cicd/core/GetEnvVar.ts index 0e0fb5e2..9c42a904 100644 --- a/cicd/core/GetEnvVar.ts +++ b/cicd/core/GetEnvVar.ts @@ -7,7 +7,7 @@ import { Utils } from "./Utils.ts"; */ const getEnvVar = (name: string, scriptFileName?: string, throwErrorIfMissing: boolean = true): string => { const value = (Deno.env.get(name) ?? "").trim(); - + if (Utils.isNothing(value) && throwErrorIfMissing) { const fileName = Utils.isNothing(scriptFileName) ? "" : `\n\t${scriptFileName}`; const errorMsg = `The '${name}' environment variable does not exist.${fileName}`; @@ -16,6 +16,6 @@ const getEnvVar = (name: string, scriptFileName?: string, throwErrorIfMissing: b } return value; -} +}; export default getEnvVar; diff --git a/cicd/core/Services/ReadMeTranspilerService.ts b/cicd/core/Services/ReadMeTranspilerService.ts index 7c16e39a..1e804777 100644 --- a/cicd/core/Services/ReadMeTranspilerService.ts +++ b/cicd/core/Services/ReadMeTranspilerService.ts @@ -1,8 +1,6 @@ -import { existsSync } from "@std/fs/exists"; +import { existsSync } from "jsr:@std/fs@^1.0.4"; import { Utils } from "../Utils.ts"; -// TODO: replace File references - /** * Transpiles the HTML content in a README.md file to markdown. */ diff --git a/cicd/core/Services/ValidateSDKVersionService.ts b/cicd/core/Services/ValidateSDKVersionService.ts index 1041e494..455cbb8a 100644 --- a/cicd/core/Services/ValidateSDKVersionService.ts +++ b/cicd/core/Services/ValidateSDKVersionService.ts @@ -58,7 +58,8 @@ export class ValidateSDKVersionService { continue; } - const errorMsg = `The current target framework version '${currentSdkVersion}' in the csproj file '${csProjFile}' does not match the expected` + + const errorMsg = + `The current target framework version '${currentSdkVersion}' in the csproj file '${csProjFile}' does not match the expected` + ` version of '${expectedSdkVersion}'. Please check the 'NET_SDK_VERSION' repository variable.`; nonMatchingVersions.push([csProjFile, errorMsg]); } else { diff --git a/cicd/core/Validators.ts b/cicd/core/Validators.ts index 810baf19..75fc4bc5 100644 --- a/cicd/core/Validators.ts +++ b/cicd/core/Validators.ts @@ -9,7 +9,7 @@ import { Utils } from "./Utils.ts"; */ const validateOrgExists = async (scriptFileName?: string): Promise => { const ownerName = getEnvVar("OWNER_NAME", scriptFileName); - const token = getEnvVar("GITHUB_TOKEN", scriptFileName) + const token = getEnvVar("GITHUB_TOKEN", scriptFileName); const orgClient = new OrgClient(ownerName, token); @@ -21,7 +21,7 @@ const validateOrgExists = async (scriptFileName?: string): Promise => { Utils.printAsGitHubError(errorMsg); Deno.exit(1); } -} +}; /** * Validates that a GitHub organization exists. @@ -31,7 +31,7 @@ const validateOrgExists = async (scriptFileName?: string): Promise => { const validateRepoExists = async (scriptFileName?: string): Promise => { const ownerName = getEnvVar("OWNER_NAME", scriptFileName); const repoName = getEnvVar("REPO_NAME", scriptFileName); - const token = getEnvVar("GITHUB_TOKEN", scriptFileName) + const token = getEnvVar("GITHUB_TOKEN", scriptFileName); const repoClient = new RepoClient(ownerName, repoName, token); @@ -42,7 +42,7 @@ const validateRepoExists = async (scriptFileName?: string): Promise => { Utils.printAsGitHubError(errorMsg); Deno.exit(1); } -} +}; /** * Validates that a GitHub milestone exists. @@ -53,7 +53,7 @@ const validateRepoExists = async (scriptFileName?: string): Promise => { const validateMilestoneExists = async (milestoneTitle: string, scriptFileName?: string): Promise => { const ownerName = getEnvVar("OWNER_NAME", scriptFileName); const repoName = getEnvVar("REPO_NAME", scriptFileName); - const token = getEnvVar("GITHUB_TOKEN", scriptFileName) + const token = getEnvVar("GITHUB_TOKEN", scriptFileName); const milestoneClient = new MilestoneClient(ownerName, repoName, token); @@ -64,6 +64,6 @@ const validateMilestoneExists = async (milestoneTitle: string, scriptFileName?: Utils.printAsGitHubError(errorMsg); Deno.exit(1); } -} +}; -export { validateOrgExists, validateRepoExists, validateMilestoneExists }; +export { validateMilestoneExists, validateOrgExists, validateRepoExists }; diff --git a/cicd/scripts/add-item-to-project.ts b/cicd/scripts/add-item-to-project.ts index 6edebcde..8140ba7d 100644 --- a/cicd/scripts/add-item-to-project.ts +++ b/cicd/scripts/add-item-to-project.ts @@ -1,4 +1,4 @@ -import { ProjectClient, IssueClient, PullRequestClient } from "../../deps.ts"; +import { IssueClient, ProjectClient, PullRequestClient } from "../../deps.ts"; import getEnvVar from "../core/GetEnvVar.ts"; import { Utils } from "../core/Utils.ts"; diff --git a/cicd/scripts/check-workflow-versions.ts b/cicd/scripts/check-workflow-versions.ts new file mode 100644 index 00000000..ec4d80e7 --- /dev/null +++ b/cicd/scripts/check-workflow-versions.ts @@ -0,0 +1,100 @@ +import { walkSync } from "jsr:@std/fs@^1.0.4"; +import { exists } from "jsr:@std/fs@^1.0.4"; +import { basename } from "jsr:@std/path@^1.0.6"; +import { TagClient } from "../../deps.ts"; +import { Utils } from "../../cicd/core/Utils.ts"; +import getEnvVar from "../../cicd/core/GetEnvVar.ts"; +import { validateOrgExists, validateRepoExists } from "../../cicd/core/Validators.ts"; + +const scriptFileName = new URL(import.meta.url).pathname.split("/").pop(); + +const ownerName = getEnvVar("OWNER_NAME", scriptFileName); +const repoName = getEnvVar("REPO_NAME", scriptFileName); +let baseDirPath = getEnvVar("BASE_DIR_PATH", scriptFileName); +baseDirPath = Utils.normalizePath(baseDirPath); +const token = getEnvVar("GITHUB_TOKEN", scriptFileName); + +await validateOrgExists(scriptFileName); +await validateRepoExists(scriptFileName); + +if (!exists(baseDirPath)) { + Utils.printAsGitHubError(`Directory '${baseDirPath}' does not exist.`); + Deno.exit(1); +} + +const yamlFiles = [...walkSync(baseDirPath, { + includeDirs: false, + includeFiles: true, + exts: [".yaml", ".yml"], +})].map((e) => e.path); + +const tagClient: TagClient = new TagClient(ownerName, repoName, token); + +const existingReleaseTags = (await tagClient.getAllTags()).map((t) => t.name); + +const workflowsToUpdate: WorkflowToUpdate[] = []; + +const reusableWorkflowRegex = /uses: .+.(yml|yaml)@v([1-9]\d*|0)\.([1-9]\d*|0)\.([1-9]\d*|0)(-preview\.([1-9]\d*))?/gm; + +type WorkflowToUpdate = { + /** + * The file path to the workflow. + */ + filePath: string; + + /** + * The reusable workflow references that need to be updated. + */ + workflowRefs: string[]; +}; + +// Search for workflow references with a version that has not been updated +yamlFiles.forEach((yamlFile) => { + const workflowToUpdate: WorkflowToUpdate = { + filePath: yamlFile, + workflowRefs: [], + }; + + const fileContent = Deno.readTextFileSync(yamlFile); + + const possibleUpdates = fileContent.match(reusableWorkflowRegex)?.map((w) => w) ?? []; + + // Check each reusable workflow reference version + possibleUpdates.forEach((possibleUpdate) => { + const fullRef = possibleUpdate.split("uses:")[1].trim(); + const workflowRefVersion = possibleUpdate.split("@")[1]; + + // If the workflow version has not been updated + if (existingReleaseTags.includes(workflowRefVersion)) { + workflowToUpdate.workflowRefs.push(fullRef); + } + }); + + if (workflowToUpdate.workflowRefs.length > 0) { + workflowsToUpdate.push(workflowToUpdate); + } +}); + +// If there are no workflows to update, then exit +if (workflowsToUpdate.length === 0) { + Utils.printAsGitHubNotice("No workflows to update."); + Deno.exit(0); +} + +const errorMsgs: string[] = []; + +// Print out all of the workflows that need to be updated as an error +workflowsToUpdate.forEach((workflowToUpdate) => { + const filePath = basename(workflowToUpdate.filePath); + + const workflowErrors: string[] = workflowToUpdate.workflowRefs.map((workflowRef) => { + return `Workflow reference '${workflowRef}' in file '${filePath}' needs to be updated.`; + }); + + errorMsgs.push(...workflowErrors); +}); + +if (errorMsgs.length > 0) { + Utils.printAsGitHubErrors(errorMsgs); + Deno.exit(1); +} diff --git a/cicd/scripts/github-release-does-not-exist.ts b/cicd/scripts/github-release-does-not-exist.ts index 1e75e0e5..841fef8a 100644 --- a/cicd/scripts/github-release-does-not-exist.ts +++ b/cicd/scripts/github-release-does-not-exist.ts @@ -12,7 +12,8 @@ const githubToken = getEnvVar("GITHUB_TOKEN", scriptFileName); // Validate the tag if (Utils.isNotValidProdVersion(tagName) && Utils.isNotValidPreviewVersion(tagName)) { - const errorMsg = `The tag name '${tagName}' is not a valid tag name. The tag name must be a valid production or preview version.`; + const errorMsg = + `The tag name '${tagName}' is not a valid tag name. The tag name must be a valid production or preview version.`; Utils.printAsGitHubError(errorMsg); Deno.exit(1); } @@ -25,7 +26,7 @@ const releaseClient: ReleaseClient = new ReleaseClient(ownerName, repoName, gith const releaseExists = await releaseClient.releaseExists(tagName); if (releaseExists) { - const errorMsg = `A release for the tag '${tagName}' already exists.` + + const errorMsg = `A release for the tag '${tagName}' already exists.` + "\nIs the tag provided the incorrect tag?"; Utils.printAsGitHubError(errorMsg); diff --git a/cicd/scripts/release-notes-do-not-exist.ts b/cicd/scripts/release-notes-do-not-exist.ts new file mode 100644 index 00000000..88181696 --- /dev/null +++ b/cicd/scripts/release-notes-do-not-exist.ts @@ -0,0 +1,15 @@ +import { existsSync } from "jsr:@std/fs@1.0.4/exists"; +import getEnvVar from "../core/GetEnvVar.ts"; +import { Utils } from "../core/Utils.ts"; + +const scriptFileName = new URL(import.meta.url).pathname.split("/").pop(); + +const notesDirPath = getEnvVar("RELEASE_NOTES_DIR_PATH", scriptFileName); +const version = getEnvVar("VERSION", scriptFileName); + +const notesFilePath = `${notesDirPath}/Release-Notes-${version}.md`; + +if (!existsSync(notesFilePath)) { + Utils.printAsGitHubError(`The release notes file '${notesFilePath}' does not exist.`); + Deno.exit(1); +} diff --git a/cicd/scripts/resolve-csproj.ts b/cicd/scripts/resolve-csproj.ts index 38c72d0b..123f7646 100644 --- a/cicd/scripts/resolve-csproj.ts +++ b/cicd/scripts/resolve-csproj.ts @@ -1,4 +1,4 @@ -import { walkSync } from "@std/fs"; +import { walkSync } from "jsr:@std/fs@^1.0.4"; import { Utils } from "../core/Utils.ts"; @@ -29,7 +29,7 @@ const filteredResults = [...walkSync(baseDirPath, { includeDirs: true, includeFiles: true, exts: [".csproj"], - match: [new RegExp(`.*${projName}\\..*`)] + match: [new RegExp(`.*${projName}\\..*`)], })].map((entry) => entry.path); if (filteredResults.length <= 0) { diff --git a/cicd/scripts/transpile-readme.ts b/cicd/scripts/transpile-readme.ts index 55a2a2b3..cf8f4a4c 100644 --- a/cicd/scripts/transpile-readme.ts +++ b/cicd/scripts/transpile-readme.ts @@ -1,4 +1,4 @@ -import { existsSync } from "@std/fs/exists"; +import { existsSync } from "jsr:@std/fs@^1.0.4"; import { Utils } from "../core/Utils.ts"; import { ReadMeTranspilerService } from "../core/Services/ReadMeTranspilerService.ts"; import getEnvVar from "../core/GetEnvVar.ts"; diff --git a/cicd/scripts/validate-tag.ts b/cicd/scripts/validate-tag.ts index 5de51b1c..57adc39c 100644 --- a/cicd/scripts/validate-tag.ts +++ b/cicd/scripts/validate-tag.ts @@ -9,7 +9,7 @@ const scriptFileName = new URL(import.meta.url).pathname.split("/").pop(); const ownerName: string = getEnvVar("OWNER_NAME", scriptFileName); const repoName: string = getEnvVar("REPO_NAME", scriptFileName); -const releaseType = getEnvVar("RELEASE_TYPE", scriptFileName).toLowerCase(); +const releaseType = getEnvVar("RELEASE_TYPE", scriptFileName).toLowerCase(); let tag: string = getEnvVar("TAG_NAME", scriptFileName); tag = tag.startsWith("v") ? tag : `v${tag}`; const token = getEnvVar("GITHUB_TOKEN", scriptFileName); @@ -22,9 +22,7 @@ if (releaseTypeInvalid) { Deno.exit(1); } -const tagIsInvalid = releaseType === "production" - ? Utils.isNotValidProdVersion(tag) - : Utils.isNotValidPreviewVersion(tag); +const tagIsInvalid = releaseType === "production" ? Utils.isNotValidProdVersion(tag) : Utils.isNotValidPreviewVersion(tag); if (tagIsInvalid) { const tagTypeStr = releaseType === "production" || releaseType === "preview" ? releaseType : "production or preview"; diff --git a/cicd/scripts/validate-version.ts b/cicd/scripts/validate-version.ts index 65582222..279a39f5 100644 --- a/cicd/scripts/validate-version.ts +++ b/cicd/scripts/validate-version.ts @@ -8,7 +8,7 @@ const scriptFileName = new URL(import.meta.url).pathname.split("/").pop(); let version: string = getEnvVar("VERSION", scriptFileName).toLowerCase(); version = version.startsWith("v") ? version : `v${version}`; -const releaseType: ReleaseType = getEnvVar("RELEASE_TYPE", scriptFileName).toLowerCase(); +const releaseType: ReleaseType = getEnvVar("RELEASE_TYPE", scriptFileName).toLowerCase(); const releaseTypeInvalid = releaseType != "production" && releaseType != "preview"; diff --git a/deno.json b/deno.json index 8a4236d7..4b6cf518 100644 --- a/deno.json +++ b/deno.json @@ -1,11 +1,11 @@ { "version": "v13.6.3", "tasks": { - "clear": "deno run -A ./.github/internal-cicd/deno-tasks/clear-screen.ts", - "build": "deno task clear && deno run -A ./.github/internal-cicd/scripts/deno-check.ts", - "lint": "deno task clear && deno lint", - "format": "deno task clear && deno fmt", - "reload-cache": "deno task clear && deno cache --lock=deno.lock --lock-write \"./cicd/scripts/mod.ts\"" + "check": "deno check ./**/*.ts", + "lint": "deno lint ./**/*.ts", + "format": "deno fmt ./**/*.ts", + "format-check": "deno fmt --check ./**/*.ts", + "reload-cache": "deno cache ./**/*.ts" }, "lint": { "include": [ diff --git a/deps.ts b/deps.ts index c5a2b09f..7039a5bd 100644 --- a/deps.ts +++ b/deps.ts @@ -1,19 +1,33 @@ // Deno Standard Library import { existsSync, walkSync } from "https://deno.land/std@0.207.0/fs/mod.ts"; -import { extname, basename, resolve } from "https://deno.land/std@0.207.0/path/mod.ts"; +import { basename, extname, resolve } from "https://deno.land/std@0.207.0/path/mod.ts"; import { isWindows } from "https://deno.land/std@0.207.0/path/_os.ts"; // KD CLIENTS import { - IssueClient, PullRequestClient, ProjectClient, UsersClient, ReleaseClient, - OrgClient, RepoClient, TagClient, LabelClient, MilestoneClient, GitClient + GitClient, + IssueClient, + LabelClient, + MilestoneClient, + OrgClient, + ProjectClient, + PullRequestClient, + ReleaseClient, + RepoClient, + TagClient, + UsersClient, } from "https://deno.land/x/kd_clients@v1.0.0-preview.8/GitHubClients/mod.ts"; import { XClient } from "https://deno.land/x/kd_clients@v1.0.0-preview.8/OtherClients/mod.ts"; import { NuGetClient } from "https://deno.land/x/kd_clients@v1.0.0-preview.8/PackageClients/mod.ts"; import { - IssueModel, LabelModel, ProjectModel, PullRequestModel, UserModel, - GitHubVarModel, MilestoneModel + GitHubVarModel, + IssueModel, + LabelModel, + MilestoneModel, + ProjectModel, + PullRequestModel, + UserModel, } from "https://deno.land/x/kd_clients@v1.0.0-preview.8/core/Models/mod.ts"; // CLIFFY @@ -23,25 +37,32 @@ import { Input } from "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/input.ts"; import chalk from "npm:chalk@5.3.0"; // LOCAL MODULES -import { Directory, CLI, File, Path } from "./cicd/core/mod.ts"; +import { CLI, Directory, File, Path } from "./cicd/core/mod.ts"; ////////////////////////////////////////////////////////////////////////////////////////////// // Deno Standard Library export { existsSync, walkSync }; -export { extname, basename, resolve }; +export { basename, extname, resolve }; export { isWindows }; // KD CLIENTS export { - IssueClient, PullRequestClient, ProjectClient, MilestoneClient, - OrgClient, RepoClient, TagClient, LabelClient, GitClient, - XClient, UsersClient, ReleaseClient, NuGetClient -}; -export type { - IssueModel, LabelModel, ProjectModel, PullRequestModel, - UserModel, GitHubVarModel, MilestoneModel + GitClient, + IssueClient, + LabelClient, + MilestoneClient, + NuGetClient, + OrgClient, + ProjectClient, + PullRequestClient, + ReleaseClient, + RepoClient, + TagClient, + UsersClient, + XClient, }; +export type { GitHubVarModel, IssueModel, LabelModel, MilestoneModel, ProjectModel, PullRequestModel, UserModel }; // CLIFFY export { Input }; @@ -50,4 +71,4 @@ export { Input }; export default chalk; // LOCAL MODULES -export { Directory, CLI, File, Path }; +export { CLI, Directory, File, Path };