diff --git a/.changeset/patch-api-timestamp-checks.md b/.changeset/patch-api-timestamp-checks.md new file mode 100644 index 00000000000..2fe7b97bcfa --- /dev/null +++ b/.changeset/patch-api-timestamp-checks.md @@ -0,0 +1,5 @@ +--- +"gh-aw": patch +--- + +Use GitHub API for lock file timestamp checks instead of repository checkout diff --git a/.github/workflows/ai-triage-campaign.lock.yml b/.github/workflows/ai-triage-campaign.lock.yml index bb9b98e4b7b..096eb2970e0 100644 --- a/.github/workflows/ai-triage-campaign.lock.yml +++ b/.github/workflows/ai-triage-campaign.lock.yml @@ -62,80 +62,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "ai-triage-campaign.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/archie.lock.yml b/.github/workflows/archie.lock.yml index 17e4e47f843..07fdd62e83a 100644 --- a/.github/workflows/archie.lock.yml +++ b/.github/workflows/archie.lock.yml @@ -99,80 +99,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "archie.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/artifacts-summary.lock.yml b/.github/workflows/artifacts-summary.lock.yml index 70dc93dea55..a2f9ce6b97d 100644 --- a/.github/workflows/artifacts-summary.lock.yml +++ b/.github/workflows/artifacts-summary.lock.yml @@ -58,80 +58,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "artifacts-summary.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index 7280dd6779e..d796e2dc172 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -71,80 +71,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "audit-workflows.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/blog-auditor.lock.yml b/.github/workflows/blog-auditor.lock.yml index e4c9f847885..ee98a5b65a1 100644 --- a/.github/workflows/blog-auditor.lock.yml +++ b/.github/workflows/blog-auditor.lock.yml @@ -59,80 +59,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "blog-auditor.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/brave.lock.yml b/.github/workflows/brave.lock.yml index e8127e48158..1fe6753e016 100644 --- a/.github/workflows/brave.lock.yml +++ b/.github/workflows/brave.lock.yml @@ -80,80 +80,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "brave.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/changeset.lock.yml b/.github/workflows/changeset.lock.yml index 417384a76e1..2c8f16fc451 100644 --- a/.github/workflows/changeset.lock.yml +++ b/.github/workflows/changeset.lock.yml @@ -83,80 +83,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "changeset.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/ci-doctor.lock.yml b/.github/workflows/ci-doctor.lock.yml index b398cfa1b31..3657d2d158e 100644 --- a/.github/workflows/ci-doctor.lock.yml +++ b/.github/workflows/ci-doctor.lock.yml @@ -78,80 +78,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "ci-doctor.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/cli-consistency-checker.lock.yml b/.github/workflows/cli-consistency-checker.lock.yml index b0aff3ed87d..2fcc4d234d8 100644 --- a/.github/workflows/cli-consistency-checker.lock.yml +++ b/.github/workflows/cli-consistency-checker.lock.yml @@ -56,80 +56,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "cli-consistency-checker.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/cli-version-checker.lock.yml b/.github/workflows/cli-version-checker.lock.yml index fa81619a091..1b9c7e1dcfb 100644 --- a/.github/workflows/cli-version-checker.lock.yml +++ b/.github/workflows/cli-version-checker.lock.yml @@ -61,80 +61,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "cli-version-checker.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index 91876a6fa55..83e22777133 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -130,80 +130,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "cloclo.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/commit-changes-analyzer.lock.yml b/.github/workflows/commit-changes-analyzer.lock.yml index 051f35b977c..53197df25a7 100644 --- a/.github/workflows/commit-changes-analyzer.lock.yml +++ b/.github/workflows/commit-changes-analyzer.lock.yml @@ -62,80 +62,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "commit-changes-analyzer.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/copilot-agent-analysis.lock.yml b/.github/workflows/copilot-agent-analysis.lock.yml index 881b3408192..8faf71d69c1 100644 --- a/.github/workflows/copilot-agent-analysis.lock.yml +++ b/.github/workflows/copilot-agent-analysis.lock.yml @@ -63,80 +63,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "copilot-agent-analysis.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/copilot-pr-nlp-analysis.lock.yml b/.github/workflows/copilot-pr-nlp-analysis.lock.yml index 90c7957b472..61c8694726b 100644 --- a/.github/workflows/copilot-pr-nlp-analysis.lock.yml +++ b/.github/workflows/copilot-pr-nlp-analysis.lock.yml @@ -64,80 +64,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "copilot-pr-nlp-analysis.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/copilot-pr-prompt-analysis.lock.yml b/.github/workflows/copilot-pr-prompt-analysis.lock.yml index cfeadda8cf1..c48915b837a 100644 --- a/.github/workflows/copilot-pr-prompt-analysis.lock.yml +++ b/.github/workflows/copilot-pr-prompt-analysis.lock.yml @@ -63,80 +63,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "copilot-pr-prompt-analysis.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/copilot-session-insights.lock.yml b/.github/workflows/copilot-session-insights.lock.yml index da8d878cf67..8a9ab183076 100644 --- a/.github/workflows/copilot-session-insights.lock.yml +++ b/.github/workflows/copilot-session-insights.lock.yml @@ -68,80 +68,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "copilot-session-insights.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/craft.lock.yml b/.github/workflows/craft.lock.yml index f7c6e2676fc..2d64b886a8e 100644 --- a/.github/workflows/craft.lock.yml +++ b/.github/workflows/craft.lock.yml @@ -81,80 +81,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "craft.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/daily-code-metrics.lock.yml b/.github/workflows/daily-code-metrics.lock.yml index 75b5811c62d..1a420355a38 100644 --- a/.github/workflows/daily-code-metrics.lock.yml +++ b/.github/workflows/daily-code-metrics.lock.yml @@ -61,80 +61,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "daily-code-metrics.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/daily-doc-updater.lock.yml b/.github/workflows/daily-doc-updater.lock.yml index c7dc2dc1386..9dc1fcdd31b 100644 --- a/.github/workflows/daily-doc-updater.lock.yml +++ b/.github/workflows/daily-doc-updater.lock.yml @@ -58,80 +58,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "daily-doc-updater.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/daily-file-diet.lock.yml b/.github/workflows/daily-file-diet.lock.yml index 89bbdc6e51e..97bb79916f5 100644 --- a/.github/workflows/daily-file-diet.lock.yml +++ b/.github/workflows/daily-file-diet.lock.yml @@ -66,80 +66,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "daily-file-diet.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index 4077263f1e5..bc190718342 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -67,80 +67,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "daily-firewall-report.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/daily-multi-device-docs-tester.lock.yml b/.github/workflows/daily-multi-device-docs-tester.lock.yml index 8a1b8d20f92..beab81cfa52 100644 --- a/.github/workflows/daily-multi-device-docs-tester.lock.yml +++ b/.github/workflows/daily-multi-device-docs-tester.lock.yml @@ -63,80 +63,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "daily-multi-device-docs-tester.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/daily-news.lock.yml b/.github/workflows/daily-news.lock.yml index 456ca21d856..ec8283c820b 100644 --- a/.github/workflows/daily-news.lock.yml +++ b/.github/workflows/daily-news.lock.yml @@ -70,80 +70,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "daily-news.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/daily-repo-chronicle.lock.yml b/.github/workflows/daily-repo-chronicle.lock.yml index 311f6315ab3..92283cc6af6 100644 --- a/.github/workflows/daily-repo-chronicle.lock.yml +++ b/.github/workflows/daily-repo-chronicle.lock.yml @@ -67,80 +67,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "daily-repo-chronicle.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/daily-team-status.lock.yml b/.github/workflows/daily-team-status.lock.yml index 0baa846cf34..c4d7d65dc2a 100644 --- a/.github/workflows/daily-team-status.lock.yml +++ b/.github/workflows/daily-team-status.lock.yml @@ -76,80 +76,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "daily-team-status.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/dependabot-go-checker.lock.yml b/.github/workflows/dependabot-go-checker.lock.yml index e6b161b3890..d9db2430a57 100644 --- a/.github/workflows/dependabot-go-checker.lock.yml +++ b/.github/workflows/dependabot-go-checker.lock.yml @@ -57,80 +57,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "dependabot-go-checker.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index 1d23e49d5da..1eee27855aa 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -66,80 +66,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "dev-hawk.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/dev.lock.yml b/.github/workflows/dev.lock.yml index 7b077529ad7..5979b215537 100644 --- a/.github/workflows/dev.lock.yml +++ b/.github/workflows/dev.lock.yml @@ -55,80 +55,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "dev.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/developer-docs-consolidator.lock.yml b/.github/workflows/developer-docs-consolidator.lock.yml index 3b9b081b197..0e4ff762b19 100644 --- a/.github/workflows/developer-docs-consolidator.lock.yml +++ b/.github/workflows/developer-docs-consolidator.lock.yml @@ -73,80 +73,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "developer-docs-consolidator.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/dictation-prompt.lock.yml b/.github/workflows/dictation-prompt.lock.yml index 1390bce6f15..b946a0e2733 100644 --- a/.github/workflows/dictation-prompt.lock.yml +++ b/.github/workflows/dictation-prompt.lock.yml @@ -60,80 +60,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "dictation-prompt.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/docs-noob-tester.lock.yml b/.github/workflows/docs-noob-tester.lock.yml index de075819a83..cd80b9247b0 100644 --- a/.github/workflows/docs-noob-tester.lock.yml +++ b/.github/workflows/docs-noob-tester.lock.yml @@ -58,80 +58,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "docs-noob-tester.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/duplicate-code-detector.lock.yml b/.github/workflows/duplicate-code-detector.lock.yml index f1180640d0c..bd35399ab3a 100644 --- a/.github/workflows/duplicate-code-detector.lock.yml +++ b/.github/workflows/duplicate-code-detector.lock.yml @@ -65,80 +65,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "duplicate-code-detector.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/example-permissions-warning.lock.yml b/.github/workflows/example-permissions-warning.lock.yml index 9112f480765..b818bfb0377 100644 --- a/.github/workflows/example-permissions-warning.lock.yml +++ b/.github/workflows/example-permissions-warning.lock.yml @@ -43,80 +43,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "example-permissions-warning.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml index c498a1a25c6..5989784f810 100644 --- a/.github/workflows/example-workflow-analyzer.lock.yml +++ b/.github/workflows/example-workflow-analyzer.lock.yml @@ -60,80 +60,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "example-workflow-analyzer.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/firewall.lock.yml b/.github/workflows/firewall.lock.yml index 06cdee6d687..734ce196e0c 100644 --- a/.github/workflows/firewall.lock.yml +++ b/.github/workflows/firewall.lock.yml @@ -43,80 +43,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "firewall.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/github-mcp-tools-report.lock.yml b/.github/workflows/github-mcp-tools-report.lock.yml index 72b3812d6cf..91b5be0f5c4 100644 --- a/.github/workflows/github-mcp-tools-report.lock.yml +++ b/.github/workflows/github-mcp-tools-report.lock.yml @@ -69,80 +69,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "github-mcp-tools-report.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/go-logger.lock.yml b/.github/workflows/go-logger.lock.yml index 43a975a8e27..d85987328d6 100644 --- a/.github/workflows/go-logger.lock.yml +++ b/.github/workflows/go-logger.lock.yml @@ -60,80 +60,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "go-logger.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/go-pattern-detector.lock.yml b/.github/workflows/go-pattern-detector.lock.yml index 47badae9356..d55b38dddbc 100644 --- a/.github/workflows/go-pattern-detector.lock.yml +++ b/.github/workflows/go-pattern-detector.lock.yml @@ -66,80 +66,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "go-pattern-detector.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/grumpy-reviewer.lock.yml b/.github/workflows/grumpy-reviewer.lock.yml index b0008691082..e2ce6a3300e 100644 --- a/.github/workflows/grumpy-reviewer.lock.yml +++ b/.github/workflows/grumpy-reviewer.lock.yml @@ -86,80 +86,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "grumpy-reviewer.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/instructions-janitor.lock.yml b/.github/workflows/instructions-janitor.lock.yml index b3b8fd21776..41d1c9b8b10 100644 --- a/.github/workflows/instructions-janitor.lock.yml +++ b/.github/workflows/instructions-janitor.lock.yml @@ -58,80 +58,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "instructions-janitor.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/issue-classifier.lock.yml b/.github/workflows/issue-classifier.lock.yml index 2da9735e51e..5eca4209762 100644 --- a/.github/workflows/issue-classifier.lock.yml +++ b/.github/workflows/issue-classifier.lock.yml @@ -72,80 +72,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "issue-classifier.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/lockfile-stats.lock.yml b/.github/workflows/lockfile-stats.lock.yml index 5d66cdf4c0f..e30c81098e5 100644 --- a/.github/workflows/lockfile-stats.lock.yml +++ b/.github/workflows/lockfile-stats.lock.yml @@ -61,80 +61,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "lockfile-stats.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index 1ca5e86aeb4..ce622ada430 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -90,80 +90,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "mcp-inspector.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/mergefest.lock.yml b/.github/workflows/mergefest.lock.yml index 98456e3e1d6..e8afbdc2353 100644 --- a/.github/workflows/mergefest.lock.yml +++ b/.github/workflows/mergefest.lock.yml @@ -76,80 +76,86 @@ jobs: comment_url: ${{ steps.react.outputs.comment-url }} reaction_id: ${{ steps.react.outputs.reaction-id }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "mergefest.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/notion-issue-summary.lock.yml b/.github/workflows/notion-issue-summary.lock.yml index 923261dd90c..4cf23b6d613 100644 --- a/.github/workflows/notion-issue-summary.lock.yml +++ b/.github/workflows/notion-issue-summary.lock.yml @@ -56,80 +56,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "notion-issue-summary.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/pdf-summary.lock.yml b/.github/workflows/pdf-summary.lock.yml index f863fabf77e..9a8ab83f9be 100644 --- a/.github/workflows/pdf-summary.lock.yml +++ b/.github/workflows/pdf-summary.lock.yml @@ -102,80 +102,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "pdf-summary.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/plan.lock.yml b/.github/workflows/plan.lock.yml index c246d96f568..1c851f755a1 100644 --- a/.github/workflows/plan.lock.yml +++ b/.github/workflows/plan.lock.yml @@ -81,80 +81,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "plan.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/poem-bot.lock.yml b/.github/workflows/poem-bot.lock.yml index 7a0f5cc5be8..911fab9942d 100644 --- a/.github/workflows/poem-bot.lock.yml +++ b/.github/workflows/poem-bot.lock.yml @@ -117,80 +117,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "poem-bot.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/pr-nitpick-reviewer.lock.yml b/.github/workflows/pr-nitpick-reviewer.lock.yml index 0a9ccad655f..7e18c57df6d 100644 --- a/.github/workflows/pr-nitpick-reviewer.lock.yml +++ b/.github/workflows/pr-nitpick-reviewer.lock.yml @@ -118,80 +118,86 @@ jobs: comment_url: ${{ steps.react.outputs.comment-url }} reaction_id: ${{ steps.react.outputs.reaction-id }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "pr-nitpick-reviewer.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index 4c6b83f62f7..beb4269edcd 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -68,80 +68,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "prompt-clustering-analysis.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index 596bb582a43..a8a69eed218 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -65,80 +65,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "python-data-charts.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index a657ef6d028..93676c242b8 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -125,80 +125,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "q.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/repo-tree-map.lock.yml b/.github/workflows/repo-tree-map.lock.yml index 756f1904ec2..f347d06f319 100644 --- a/.github/workflows/repo-tree-map.lock.yml +++ b/.github/workflows/repo-tree-map.lock.yml @@ -59,80 +59,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "repo-tree-map.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/repository-quality-improver.lock.yml b/.github/workflows/repository-quality-improver.lock.yml index 63c8c1d3248..58eee6d7783 100644 --- a/.github/workflows/repository-quality-improver.lock.yml +++ b/.github/workflows/repository-quality-improver.lock.yml @@ -69,80 +69,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "repository-quality-improver.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/research.lock.yml b/.github/workflows/research.lock.yml index 9abc49ec05c..b8f771df52b 100644 --- a/.github/workflows/research.lock.yml +++ b/.github/workflows/research.lock.yml @@ -63,80 +63,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "research.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml index 2991d510664..253bff85db9 100644 --- a/.github/workflows/safe-output-health.lock.yml +++ b/.github/workflows/safe-output-health.lock.yml @@ -66,80 +66,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "safe-output-health.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/schema-consistency-checker.lock.yml b/.github/workflows/schema-consistency-checker.lock.yml index abb84e6066c..6b3be565eb4 100644 --- a/.github/workflows/schema-consistency-checker.lock.yml +++ b/.github/workflows/schema-consistency-checker.lock.yml @@ -62,80 +62,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "schema-consistency-checker.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/scout.lock.yml b/.github/workflows/scout.lock.yml index 933d2ba5ffa..388e59c6e85 100644 --- a/.github/workflows/scout.lock.yml +++ b/.github/workflows/scout.lock.yml @@ -128,80 +128,86 @@ jobs: reaction_id: ${{ steps.react.outputs.reaction-id }} text: ${{ steps.compute-text.outputs.text }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "scout.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/security-fix-pr.lock.yml b/.github/workflows/security-fix-pr.lock.yml index 4b69b0347d5..b007974abea 100644 --- a/.github/workflows/security-fix-pr.lock.yml +++ b/.github/workflows/security-fix-pr.lock.yml @@ -56,80 +56,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "security-fix-pr.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/semantic-function-refactor.lock.yml b/.github/workflows/semantic-function-refactor.lock.yml index a5f5bb05a95..a281c70c02d 100644 --- a/.github/workflows/semantic-function-refactor.lock.yml +++ b/.github/workflows/semantic-function-refactor.lock.yml @@ -66,80 +66,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "semantic-function-refactor.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 5a0c8f2f2b5..60ec9a3f3a1 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -71,80 +71,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "smoke-claude.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/smoke-codex.lock.yml b/.github/workflows/smoke-codex.lock.yml index 4b4ada8c57d..25d260d3a72 100644 --- a/.github/workflows/smoke-codex.lock.yml +++ b/.github/workflows/smoke-codex.lock.yml @@ -67,80 +67,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "smoke-codex.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 9bd56bb4544..58e1fda84e6 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -67,80 +67,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "smoke-copilot.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/smoke-detector.lock.yml b/.github/workflows/smoke-detector.lock.yml index d2a28ad3f52..c2f4ac14dd7 100644 --- a/.github/workflows/smoke-detector.lock.yml +++ b/.github/workflows/smoke-detector.lock.yml @@ -110,80 +110,86 @@ jobs: comment_url: ${{ steps.react.outputs.comment-url }} reaction_id: ${{ steps.react.outputs.reaction-id }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "smoke-detector.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml index 5a9a395d406..56bd78b09b1 100644 --- a/.github/workflows/static-analysis-report.lock.yml +++ b/.github/workflows/static-analysis-report.lock.yml @@ -65,80 +65,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "static-analysis-report.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/super-linter.lock.yml b/.github/workflows/super-linter.lock.yml index 00313ce1148..e5b19d7a85a 100644 --- a/.github/workflows/super-linter.lock.yml +++ b/.github/workflows/super-linter.lock.yml @@ -67,80 +67,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "super-linter.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/technical-doc-writer.lock.yml b/.github/workflows/technical-doc-writer.lock.yml index 9a726f312ff..daeaf669fb5 100644 --- a/.github/workflows/technical-doc-writer.lock.yml +++ b/.github/workflows/technical-doc-writer.lock.yml @@ -74,80 +74,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "technical-doc-writer.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/test-claude-oauth-workflow.lock.yml b/.github/workflows/test-claude-oauth-workflow.lock.yml index 1006b85491b..58a9b383135 100644 --- a/.github/workflows/test-claude-oauth-workflow.lock.yml +++ b/.github/workflows/test-claude-oauth-workflow.lock.yml @@ -49,80 +49,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "test-claude-oauth-workflow.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/test-jqschema.lock.yml b/.github/workflows/test-jqschema.lock.yml index 06891c86c1c..4503742d27d 100644 --- a/.github/workflows/test-jqschema.lock.yml +++ b/.github/workflows/test-jqschema.lock.yml @@ -45,80 +45,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "test-jqschema.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/test-manual-approval.lock.yml b/.github/workflows/test-manual-approval.lock.yml index 57756c383fb..18770cdd9a1 100644 --- a/.github/workflows/test-manual-approval.lock.yml +++ b/.github/workflows/test-manual-approval.lock.yml @@ -51,80 +51,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "test-manual-approval.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/test-ollama-threat-detection.lock.yml b/.github/workflows/test-ollama-threat-detection.lock.yml index fe9670afdc8..7ea6ce75b48 100644 --- a/.github/workflows/test-ollama-threat-detection.lock.yml +++ b/.github/workflows/test-ollama-threat-detection.lock.yml @@ -54,80 +54,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "test-ollama-threat-detection.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/test-post-steps.lock.yml b/.github/workflows/test-post-steps.lock.yml index 25907f11b6e..3d13ef46c9c 100644 --- a/.github/workflows/test-post-steps.lock.yml +++ b/.github/workflows/test-post-steps.lock.yml @@ -41,80 +41,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "test-post-steps.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/test-secret-masking.lock.yml b/.github/workflows/test-secret-masking.lock.yml index d7eeb0d3a16..203c8763aa4 100644 --- a/.github/workflows/test-secret-masking.lock.yml +++ b/.github/workflows/test-secret-masking.lock.yml @@ -50,80 +50,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "test-secret-masking.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/test-svelte.lock.yml b/.github/workflows/test-svelte.lock.yml index d35576de681..18137ceeedd 100644 --- a/.github/workflows/test-svelte.lock.yml +++ b/.github/workflows/test-svelte.lock.yml @@ -47,80 +47,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "test-svelte.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/tidy.lock.yml b/.github/workflows/tidy.lock.yml index 0d6d01117de..89010438476 100644 --- a/.github/workflows/tidy.lock.yml +++ b/.github/workflows/tidy.lock.yml @@ -93,80 +93,86 @@ jobs: comment_url: ${{ steps.react.outputs.comment-url }} reaction_id: ${{ steps.react.outputs.reaction-id }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "tidy.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/typist.lock.yml b/.github/workflows/typist.lock.yml index 1ce9e5ccca6..95bb71b6a45 100644 --- a/.github/workflows/typist.lock.yml +++ b/.github/workflows/typist.lock.yml @@ -66,80 +66,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "typist.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/unbloat-docs.lock.yml b/.github/workflows/unbloat-docs.lock.yml index d098c28ad60..c482b419b46 100644 --- a/.github/workflows/unbloat-docs.lock.yml +++ b/.github/workflows/unbloat-docs.lock.yml @@ -95,80 +95,86 @@ jobs: comment_url: ${{ steps.react.outputs.comment-url }} reaction_id: ${{ steps.react.outputs.reaction-id }} steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "unbloat-docs.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); } - if (!workflowExists || !lockExists) { + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/video-analyzer.lock.yml b/.github/workflows/video-analyzer.lock.yml index b63fbb0bc77..2fbcdaa9529 100644 --- a/.github/workflows/video-analyzer.lock.yml +++ b/.github/workflows/video-analyzer.lock.yml @@ -62,80 +62,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "video-analyzer.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/.github/workflows/weekly-issue-summary.lock.yml b/.github/workflows/weekly-issue-summary.lock.yml index b711fa5f104..dc0eb5f984e 100644 --- a/.github/workflows/weekly-issue-summary.lock.yml +++ b/.github/workflows/weekly-issue-summary.lock.yml @@ -64,80 +64,86 @@ jobs: permissions: contents: read steps: - - name: Checkout workflows - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - with: - sparse-checkout: | - .github/workflows - sparse-checkout-cone-mode: false - fetch-depth: 1 - persist-credentials: false - name: Check workflow file timestamps uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 env: GH_AW_WORKFLOW_FILE: "weekly-issue-summary.lock.yml" with: script: | - const fs = require("fs"); - const path = require("path"); async function main() { - const workspace = process.env.GITHUB_WORKSPACE; const workflowFile = process.env.GH_AW_WORKFLOW_FILE; - if (!workspace) { - core.setFailed("Configuration error: GITHUB_WORKSPACE not available."); - return; - } if (!workflowFile) { core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); return; } - const workflowBasename = path.basename(workflowFile, ".lock.yml"); - const workflowMdFile = path.join(workspace, ".github", "workflows", `${workflowBasename}.md`); - const lockFile = path.join(workspace, ".github", "workflows", workflowFile); - core.info(`Checking workflow timestamps:`); - core.info(` Source: ${workflowMdFile}`); - core.info(` Lock file: ${lockFile}`); - let workflowExists = false; - let lockExists = false; - try { - fs.accessSync(workflowMdFile, fs.constants.F_OK); - workflowExists = true; - } catch (error) { - core.info(`Source file does not exist: ${workflowMdFile}`); + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + const { owner, repo } = context.repo; + const ref = context.sha; + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } } - try { - fs.accessSync(lockFile, fs.constants.F_OK); - lockExists = true; - } catch (error) { - core.info(`Lock file does not exist: ${lockFile}`); + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); } - if (!workflowExists || !lockExists) { + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + if (!workflowCommit || !lockCommit) { core.info("Skipping timestamp check - one or both files not found"); return; } - const workflowStat = fs.statSync(workflowMdFile); - const lockStat = fs.statSync(lockFile); - const workflowMtime = workflowStat.mtime.getTime(); - const lockMtime = lockStat.mtime.getTime(); - core.info(` Source modified: ${workflowStat.mtime.toISOString()}`); - core.info(` Lock modified: ${lockStat.mtime.toISOString()}`); - if (workflowMtime > lockMtime) { - const warningMessage = `WARNING: Lock file '${lockFile}' is outdated! The workflow file '${workflowMdFile}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; core.error(warningMessage); - const workflowTimestamp = workflowStat.mtime.toISOString(); - const lockTimestamp = lockStat.mtime.toISOString(); - const gitSha = process.env.GITHUB_SHA; + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); let summary = core.summary .addRaw("### ⚠️ Workflow Lock File Warning\n\n") .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") .addRaw("**Files:**\n") - .addRaw(`- Source: \`${workflowMdFile}\` (modified: ${workflowTimestamp})\n`) - .addRaw(`- Lock: \`${lockFile}\` (modified: ${lockTimestamp})\n\n`); - if (gitSha) { - summary = summary.addRaw(`**Git Commit:** \`${gitSha}\`\n\n`); - } - summary = summary.addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); } else { core.info("✅ Lock file is up to date"); } diff --git a/docs/src/content/docs/reference/frontmatter-full.md b/docs/src/content/docs/reference/frontmatter-full.md index 8e047bc93c8..4321aac425a 100644 --- a/docs/src/content/docs/reference/frontmatter-full.md +++ b/docs/src/content/docs/reference/frontmatter-full.md @@ -685,7 +685,7 @@ runs-on: labels: [] # Array of strings -# Workflow timeout in minutes (GitHub Actions standard field). Defaults to 15 +# Workflow timeout in minutes (GitHub Actions standard field). Defaults to 20 # minutes for agentic workflows. Has sensible defaults and can typically be # omitted. # (optional) @@ -908,7 +908,8 @@ engine: model: "example-value" # Maximum number of chat iterations per run. Helps prevent runaway loops and - # control costs. Has sensible defaults and can typically be omitted. + # control costs. Has sensible defaults and can typically be omitted. Note: Only + # supported by the claude engine. # (optional) max-turns: 1 @@ -1330,6 +1331,29 @@ safe-outputs: # (optional) # This field supports multiple formats (oneOf): + # Option 1: Configuration for managing GitHub Projects v2 boards. Smart tool that + # auto-detects whether to create a project (if missing), add issue/PR items, or + # update custom fields on existing items. Requires repository-projects: write + # permission. Safe output items produced by the agent use type=update_project and + # may include: project (board name), content_type (issue|pull_request), + # content_number, and a fields object mapping project field names to values. + update-project: + # Maximum number of project operations to perform (default: 10). Each operation + # may add a project item, or update its fields. + # (optional) + max: 1 + + # GitHub token to use for this specific output type. Overrides global github-token + # if specified. + # (optional) + github-token: "${{ secrets.GITHUB_TOKEN }}" + + # Option 2: Enable project management with default configuration (max=10) + update-project: null + + # (optional) + # This field supports multiple formats (oneOf): + # Option 1: Configuration for creating GitHub discussions from agentic workflow # output create-discussion: @@ -1404,7 +1428,10 @@ safe-outputs: # This field supports multiple formats (oneOf): # Option 1: Configuration for creating GitHub pull requests from agentic workflow - # output + # output. Note: The max parameter is not supported for pull requests - workflows + # are always limited to creating 1 pull request per run. This design decision + # prevents workflow runs from creating excessive PRs and maintains repository + # integrity. create-pull-request: # Optional prefix for the pull request title # (optional) diff --git a/docs/src/content/docs/status.mdx b/docs/src/content/docs/status.mdx index 3be18aefd6c..614c7a47333 100644 --- a/docs/src/content/docs/status.mdx +++ b/docs/src/content/docs/status.mdx @@ -10,6 +10,7 @@ Status of all agentic workflows. [Browse source files](https://github.com/github | Workflow | Agent | Status | Schedule | Command | |:---------|:-----:|:------:|:--------:|:-------:| | [Agentic Workflow Audit Agent](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/audit-workflows.md) | claude | [![Agentic Workflow Audit Agent](https://github.com/githubnext/gh-aw/actions/workflows/audit-workflows.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/audit-workflows.lock.yml) | `0 0 * * *` | - | +| [AI Triage Campaign](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/ai-triage-campaign.md) | copilot | [![AI Triage Campaign](https://github.com/githubnext/gh-aw/actions/workflows/ai-triage-campaign.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/ai-triage-campaign.lock.yml) | - | - | | [Archie](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/archie.md) | copilot | [![Archie](https://github.com/githubnext/gh-aw/actions/workflows/archie.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/archie.lock.yml) | - | `/archie` | | [Artifacts Summary](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/artifacts-summary.md) | copilot | [![Artifacts Summary](https://github.com/githubnext/gh-aw/actions/workflows/artifacts-summary.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/artifacts-summary.lock.yml) | `0 6 * * 0` | - | | [Basic Research Agent](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/research.md) | copilot | [![Basic Research Agent](https://github.com/githubnext/gh-aw/actions/workflows/research.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/research.lock.yml) | - | - | @@ -17,7 +18,7 @@ Status of all agentic workflows. [Browse source files](https://github.com/github | [Brave Web Search Agent](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/brave.md) | copilot | [![Brave Web Search Agent](https://github.com/githubnext/gh-aw/actions/workflows/brave.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/brave.lock.yml) | - | `/brave` | | [Changeset Generator](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/changeset.md) | copilot | [![Changeset Generator](https://github.com/githubnext/gh-aw/actions/workflows/changeset.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/changeset.lock.yml) | - | - | | [CI Failure Doctor](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/ci-doctor.md) | copilot | [![CI Failure Doctor](https://github.com/githubnext/gh-aw/actions/workflows/ci-doctor.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/ci-doctor.lock.yml) | - | - | -| [Claude Command & Label Processor - `/cloclo` ✨](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/cloclo.md) | claude | [![Claude Command & Label Processor - `/cloclo` ✨](https://github.com/githubnext/gh-aw/actions/workflows/cloclo.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/cloclo.lock.yml) | - | `/cloclo` | +| [Claude Command Processor - /cloclo](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/cloclo.md) | claude | [![Claude Command Processor - /cloclo](https://github.com/githubnext/gh-aw/actions/workflows/cloclo.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/cloclo.lock.yml) | - | `/cloclo` | | [CLI Consistency Checker](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/cli-consistency-checker.md) | copilot | [![CLI Consistency Checker](https://github.com/githubnext/gh-aw/actions/workflows/cli-consistency-checker.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/cli-consistency-checker.lock.yml) | `0 13 * * 1-5` | - | | [CLI Version Checker](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/cli-version-checker.md) | copilot | [![CLI Version Checker](https://github.com/githubnext/gh-aw/actions/workflows/cli-version-checker.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/cli-version-checker.lock.yml) | `0 15 * * *` | - | | [Commit Changes Analyzer](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/commit-changes-analyzer.md) | claude | [![Commit Changes Analyzer](https://github.com/githubnext/gh-aw/actions/workflows/commit-changes-analyzer.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/commit-changes-analyzer.lock.yml) | - | - | @@ -28,14 +29,16 @@ Status of all agentic workflows. [Browse source files](https://github.com/github | [Copilot Session Insights](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/copilot-session-insights.md) | claude | [![Copilot Session Insights](https://github.com/githubnext/gh-aw/actions/workflows/copilot-session-insights.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/copilot-session-insights.lock.yml) | `0 16 * * *` | - | | [Daily Code Metrics and Trend Tracking Agent](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-code-metrics.md) | claude | [![Daily Code Metrics and Trend Tracking Agent](https://github.com/githubnext/gh-aw/actions/workflows/daily-code-metrics.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-code-metrics.lock.yml) | `0 8 * * *` | - | | [Daily Documentation Updater](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-doc-updater.md) | claude | [![Daily Documentation Updater](https://github.com/githubnext/gh-aw/actions/workflows/daily-doc-updater.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-doc-updater.lock.yml) | `0 6 * * *` | - | +| [Daily File Diet](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-file-diet.md) | codex | [![Daily File Diet](https://github.com/githubnext/gh-aw/actions/workflows/daily-file-diet.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-file-diet.lock.yml) | `0 13 * * 1-5` | - | | [Daily Firewall Logs Collector and Reporter](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-firewall-report.md) | copilot | [![Daily Firewall Logs Collector and Reporter](https://github.com/githubnext/gh-aw/actions/workflows/daily-firewall-report.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-firewall-report.lock.yml) | `0 10 * * *` | - | | [Daily News](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-news.md) | copilot | [![Daily News](https://github.com/githubnext/gh-aw/actions/workflows/daily-news.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-news.lock.yml) | `0 9 * * 1-5` | - | | [Daily Team Status](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/daily-team-status.md) | copilot | [![Daily Team Status](https://github.com/githubnext/gh-aw/actions/workflows/daily-team-status.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/daily-team-status.lock.yml) | `0 9 * * 1-5` | - | -| [Dependabot Go Module Dependency Checker](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/dependabot-go-checker.md) | copilot | [![Dependabot Go Module Dependency Checker](https://github.com/githubnext/gh-aw/actions/workflows/dependabot-go-checker.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/dependabot-go-checker.lock.yml) | `0 9 * * 1,3,5` | - | +| [Dependabot Dependency Checker](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/dependabot-go-checker.md) | copilot | [![Dependabot Dependency Checker](https://github.com/githubnext/gh-aw/actions/workflows/dependabot-go-checker.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/dependabot-go-checker.lock.yml) | `0 9 * * 1,3,5` | - | | [Dev](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/dev.md) | copilot | [![Dev](https://github.com/githubnext/gh-aw/actions/workflows/dev.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/dev.lock.yml) | - | - | | [Dev Hawk](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/dev-hawk.md) | copilot | [![Dev Hawk](https://github.com/githubnext/gh-aw/actions/workflows/dev-hawk.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/dev-hawk.lock.yml) | - | - | | [Developer Documentation Consolidator](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/developer-docs-consolidator.md) | claude | [![Developer Documentation Consolidator](https://github.com/githubnext/gh-aw/actions/workflows/developer-docs-consolidator.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/developer-docs-consolidator.lock.yml) | `17 3 * * *` | - | | [Dictation Prompt Generator](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/dictation-prompt.md) | copilot | [![Dictation Prompt Generator](https://github.com/githubnext/gh-aw/actions/workflows/dictation-prompt.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/dictation-prompt.lock.yml) | `0 6 * * 0` | - | +| [Documentation Noob Tester](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/docs-noob-tester.md) | copilot | [![Documentation Noob Tester](https://github.com/githubnext/gh-aw/actions/workflows/docs-noob-tester.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/docs-noob-tester.lock.yml) | `0 10 * * *` | - | | [Documentation Unbloat](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/unbloat-docs.md) | claude | [![Documentation Unbloat](https://github.com/githubnext/gh-aw/actions/workflows/unbloat-docs.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/unbloat-docs.lock.yml) | `0 22 * * *` | `/unbloat` | | [Duplicate Code Detector](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/duplicate-code-detector.md) | codex | [![Duplicate Code Detector](https://github.com/githubnext/gh-aw/actions/workflows/duplicate-code-detector.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/duplicate-code-detector.lock.yml) | `0 21 * * *` | - | | [Example: Properly Provisioned Permissions](https://github.com/githubnext/gh-aw/blob/main/.github/workflows/example-permissions-warning.md) | copilot | [![Example: Properly Provisioned Permissions](https://github.com/githubnext/gh-aw/actions/workflows/example-permissions-warning.lock.yml/badge.svg)](https://github.com/githubnext/gh-aw/actions/workflows/example-permissions-warning.lock.yml) | - | - | diff --git a/pkg/workflow/activation_checkout_test.go b/pkg/workflow/activation_checkout_test.go index 0918feb30bc..1819154e39b 100644 --- a/pkg/workflow/activation_checkout_test.go +++ b/pkg/workflow/activation_checkout_test.go @@ -7,16 +7,16 @@ import ( "testing" ) -// TestActivationJobCheckoutStep tests that the activation job always includes -// a shallow checkout step for the timestamp check -func TestActivationJobCheckoutStep(t *testing.T) { +// TestActivationJobNoCheckoutStep tests that the activation job uses GitHub API +// instead of checking out the repository for the timestamp check +func TestActivationJobNoCheckoutStep(t *testing.T) { tests := []struct { name string frontmatter string description string }{ { - name: "basic workflow includes activation checkout", + name: "basic workflow has no checkout in activation", frontmatter: `--- on: issues: @@ -26,10 +26,10 @@ permissions: issues: write engine: claude ---`, - description: "Activation job should include shallow checkout for timestamp check", + description: "Activation job should not include checkout step - uses GitHub API instead", }, { - name: "workflow without contents permission includes activation checkout", + name: "workflow without contents permission has no checkout in activation", frontmatter: `--- on: issues: @@ -38,10 +38,10 @@ permissions: issues: write engine: claude ---`, - description: "Activation job should include checkout even when main job doesn't need it", + description: "Activation job should not include checkout - uses GitHub API instead", }, { - name: "workflow with reaction includes activation checkout", + name: "workflow with reaction has no checkout in activation", frontmatter: `--- on: issues: @@ -51,7 +51,7 @@ permissions: issues: write engine: claude ---`, - description: "Activation job with reaction should include checkout", + description: "Activation job with reaction should not include checkout - uses GitHub API instead", }, } @@ -122,40 +122,40 @@ engine: claude activationJobSection := lockContentStr[activationJobStart:activationJobEnd] - // Verify checkout step is present - if !strings.Contains(activationJobSection, "actions/checkout@") { - t.Errorf("%s: Activation job should contain checkout step\nSection:\n%s", + // Verify checkout step is NOT present (should use GitHub API instead) + if strings.Contains(activationJobSection, "actions/checkout@") { + t.Errorf("%s: Activation job should NOT contain checkout step - should use GitHub API\nSection:\n%s", tt.description, activationJobSection) } - // Verify it's a sparse checkout - if !strings.Contains(activationJobSection, "sparse-checkout:") { - t.Errorf("%s: Checkout should use sparse-checkout", tt.description) + // Verify sparse checkout config is NOT present + if strings.Contains(activationJobSection, "sparse-checkout:") { + t.Errorf("%s: Should not use sparse-checkout - uses GitHub API", tt.description) } - // Verify it checks out .github/workflows - if !strings.Contains(activationJobSection, ".github/workflows") { - t.Errorf("%s: Should checkout .github/workflows directory", tt.description) + // Verify it does NOT checkout .github/workflows + if strings.Contains(activationJobSection, "Checkout workflows") { + t.Errorf("%s: Should not have 'Checkout workflows' step - uses GitHub API", tt.description) } - // Verify shallow clone - if !strings.Contains(activationJobSection, "fetch-depth: 1") { - t.Errorf("%s: Should use shallow clone (fetch-depth: 1)", tt.description) + // Verify timestamp check step is present + if !strings.Contains(activationJobSection, "Check workflow file timestamps") { + t.Errorf("%s: Should contain timestamp check step", tt.description) } - // Verify persist-credentials: false - if !strings.Contains(activationJobSection, "persist-credentials: false") { - t.Errorf("%s: Should set persist-credentials: false", tt.description) + // Verify it uses GitHub API (checks for API-specific functions) + if !strings.Contains(activationJobSection, "github.rest.repos.listCommits") { + t.Errorf("%s: Should use GitHub API (github.rest.repos.listCommits)", tt.description) } - // Verify sparse-checkout-cone-mode: false - if !strings.Contains(activationJobSection, "sparse-checkout-cone-mode: false") { - t.Errorf("%s: Should set sparse-checkout-cone-mode: false", tt.description) + // Verify it uses context.repo + if !strings.Contains(activationJobSection, "context.repo") { + t.Errorf("%s: Should use context.repo for GitHub API access", tt.description) } - // Verify timestamp check step is present after checkout - if !strings.Contains(activationJobSection, "Check workflow file timestamps") { - t.Errorf("%s: Should contain timestamp check step", tt.description) + // Verify it shows output via core.info + if !strings.Contains(activationJobSection, "core.info") { + t.Errorf("%s: Should use core.info for output", tt.description) } }) } diff --git a/pkg/workflow/compiler_jobs.go b/pkg/workflow/compiler_jobs.go index cb699930df0..5fa80877df3 100644 --- a/pkg/workflow/compiler_jobs.go +++ b/pkg/workflow/compiler_jobs.go @@ -537,18 +537,8 @@ func (c *Compiler) buildActivationJob(data *WorkflowData, preActivationJobCreate // Team member check is now handled by the separate check_membership job // No inline role checks needed in the task job anymore - // Add shallow checkout for timestamp check - // Only checkout .github/workflows directory for minimal performance impact - steps = append(steps, " - name: Checkout workflows\n") - steps = append(steps, fmt.Sprintf(" uses: %s\n", GetActionPin("actions/checkout"))) - steps = append(steps, " with:\n") - steps = append(steps, " sparse-checkout: |\n") - steps = append(steps, " .github/workflows\n") - steps = append(steps, " sparse-checkout-cone-mode: false\n") - steps = append(steps, " fetch-depth: 1\n") - steps = append(steps, " persist-credentials: false\n") - - // Add timestamp check for lock file vs source file + // Add timestamp check for lock file vs source file using GitHub API + // No checkout step needed - uses GitHub API to check commit times steps = append(steps, " - name: Check workflow file timestamps\n") steps = append(steps, fmt.Sprintf(" uses: %s\n", GetActionPin("actions/github-script"))) steps = append(steps, " env:\n") @@ -556,8 +546,8 @@ func (c *Compiler) buildActivationJob(data *WorkflowData, preActivationJobCreate steps = append(steps, " with:\n") steps = append(steps, " script: |\n") - // Add the JavaScript script with proper indentation - formattedScript := FormatJavaScriptForYAML(checkWorkflowTimestampScript) + // Add the JavaScript script with proper indentation (using API-based version) + formattedScript := FormatJavaScriptForYAML(checkWorkflowTimestampAPIScript) steps = append(steps, formattedScript...) // Use inlined compute-text script only if needed (no shared action) @@ -643,10 +633,10 @@ func (c *Compiler) buildActivationJob(data *WorkflowData, preActivationJobCreate activationCondition = c.combineJobIfConditions(activationCondition, workflowRunRepoSafety) } - // Set permissions - activation job always needs contents:read for checkout step + // Set permissions - activation job always needs contents:read for GitHub API access // Also add reaction permissions if reaction is configured and not "none" permsMap := map[PermissionScope]PermissionLevel{ - PermissionContents: PermissionRead, // Always needed for checkout step + PermissionContents: PermissionRead, // Always needed for GitHub API access to check file commits } if data.AIReaction != "" && data.AIReaction != "none" { diff --git a/pkg/workflow/js.go b/pkg/workflow/js.go index d84dec3f8b7..85ac173c89e 100644 --- a/pkg/workflow/js.go +++ b/pkg/workflow/js.go @@ -25,8 +25,8 @@ var checkStopTimeScript string //go:embed js/check_command_position.cjs var checkCommandPositionScript string -//go:embed js/check_workflow_timestamp.cjs -var checkWorkflowTimestampScript string +//go:embed js/check_workflow_timestamp_api.cjs +var checkWorkflowTimestampAPIScript string //go:embed js/log_parser_bootstrap.cjs var logParserBootstrapScript string diff --git a/pkg/workflow/js/check_workflow_timestamp_api.cjs b/pkg/workflow/js/check_workflow_timestamp_api.cjs new file mode 100644 index 00000000000..998a08a17b3 --- /dev/null +++ b/pkg/workflow/js/check_workflow_timestamp_api.cjs @@ -0,0 +1,116 @@ +// @ts-check +/// + +/** + * Check workflow file timestamps using GitHub API to detect outdated lock files + * This script compares the last commit time of the source .md file + * with the compiled .lock.yml file and warns if recompilation is needed + */ + +async function main() { + const workflowFile = process.env.GH_AW_WORKFLOW_FILE; + + if (!workflowFile) { + core.setFailed("Configuration error: GH_AW_WORKFLOW_FILE not available."); + return; + } + + // Construct file paths + const workflowBasename = workflowFile.replace(".lock.yml", ""); + const workflowMdPath = `.github/workflows/${workflowBasename}.md`; + const lockFilePath = `.github/workflows/${workflowFile}`; + + core.info(`Checking workflow timestamps using GitHub API:`); + core.info(` Source: ${workflowMdPath}`); + core.info(` Lock file: ${lockFilePath}`); + + const { owner, repo } = context.repo; + const ref = context.sha; + + // Helper function to get the last commit for a file + async function getLastCommitForFile(path) { + try { + const response = await github.rest.repos.listCommits({ + owner, + repo, + path, + per_page: 1, + sha: ref, + }); + + if (response.data && response.data.length > 0) { + const commit = response.data[0]; + return { + sha: commit.sha, + date: commit.commit.committer.date, + message: commit.commit.message, + }; + } + return null; + } catch (error) { + core.info(`Could not fetch commit for ${path}: ${error.message}`); + return null; + } + } + + // Fetch last commits for both files + const workflowCommit = await getLastCommitForFile(workflowMdPath); + const lockCommit = await getLastCommitForFile(lockFilePath); + + // Handle cases where files don't exist + if (!workflowCommit) { + core.info(`Source file does not exist: ${workflowMdPath}`); + } + + if (!lockCommit) { + core.info(`Lock file does not exist: ${lockFilePath}`); + } + + if (!workflowCommit || !lockCommit) { + core.info("Skipping timestamp check - one or both files not found"); + return; + } + + // Parse dates for comparison + const workflowDate = new Date(workflowCommit.date); + const lockDate = new Date(lockCommit.date); + + core.info(` Source last commit: ${workflowDate.toISOString()} (${workflowCommit.sha.substring(0, 7)})`); + core.info(` Lock last commit: ${lockDate.toISOString()} (${lockCommit.sha.substring(0, 7)})`); + + // Check if workflow file is newer than lock file + if (workflowDate > lockDate) { + const warningMessage = `WARNING: Lock file '${lockFilePath}' is outdated! The workflow file '${workflowMdPath}' has been modified more recently. Run 'gh aw compile' to regenerate the lock file.`; + + core.error(warningMessage); + + // Format timestamps and commits for display + const workflowTimestamp = workflowDate.toISOString(); + const lockTimestamp = lockDate.toISOString(); + + // Add summary to GitHub Step Summary + let summary = core.summary + .addRaw("### ⚠️ Workflow Lock File Warning\n\n") + .addRaw("**WARNING**: Lock file is outdated and needs to be regenerated.\n\n") + .addRaw("**Files:**\n") + .addRaw(`- Source: \`${workflowMdPath}\`\n`) + .addRaw(` - Last commit: ${workflowTimestamp}\n`) + .addRaw( + ` - Commit SHA: [\`${workflowCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${workflowCommit.sha})\n` + ) + .addRaw(`- Lock: \`${lockFilePath}\`\n`) + .addRaw(` - Last commit: ${lockTimestamp}\n`) + .addRaw(` - Commit SHA: [\`${lockCommit.sha.substring(0, 7)}\`](https://github.com/${owner}/${repo}/commit/${lockCommit.sha})\n\n`) + .addRaw("**Action Required:** Run `gh aw compile` to regenerate the lock file.\n\n"); + + await summary.write(); + } else if (workflowCommit.sha === lockCommit.sha) { + core.info("✅ Lock file is up to date (same commit)"); + } else { + core.info("✅ Lock file is up to date"); + } +} + +main().catch(error => { + core.setFailed(error instanceof Error ? error.message : String(error)); +}); diff --git a/pkg/workflow/task_and_reaction_permissions_test.go b/pkg/workflow/task_and_reaction_permissions_test.go index 2b7d1e155bf..41232fe6b04 100644 --- a/pkg/workflow/task_and_reaction_permissions_test.go +++ b/pkg/workflow/task_and_reaction_permissions_test.go @@ -65,23 +65,25 @@ The activation job references text output: "${{ needs.activation.outputs.text }} t.Error("Expected activation job to be present in generated workflow") } - // Test 2: Verify activation job has checkout step for timestamp check (sparse checkout) + // Test 2: Verify activation job does NOT have checkout step (uses GitHub API instead) activationJobSection := extractJobSection(lockContentStr, constants.ActivationJobName) - if !strings.Contains(activationJobSection, "actions/checkout") { - t.Error("Activation job should contain actions/checkout step for timestamp check") + if strings.Contains(activationJobSection, "actions/checkout") { + t.Error("Activation job should NOT contain actions/checkout step - should use GitHub API instead") } - // Verify it's a sparse checkout of workflows directory - if !strings.Contains(activationJobSection, "sparse-checkout:") { - t.Error("Activation job checkout should use sparse-checkout") + // Verify it does NOT use sparse checkout + if strings.Contains(activationJobSection, "sparse-checkout:") { + t.Error("Activation job should NOT use sparse-checkout - uses GitHub API instead") } - if !strings.Contains(activationJobSection, ".github/workflows") { - t.Error("Activation job checkout should checkout .github/workflows directory") + + // Verify it uses GitHub API for timestamp check + if !strings.Contains(activationJobSection, "github.rest.repos.listCommits") { + t.Error("Activation job should use GitHub API (github.rest.repos.listCommits) for timestamp check") } - // Test 3: Verify activation job has contents: read permission for checkout step + // Test 3: Verify activation job has contents: read permission for GitHub API access if !strings.Contains(activationJobSection, "contents: read") { - t.Error("Activation job should have contents: read permission for checkout step") + t.Error("Activation job should have contents: read permission for GitHub API access") } // Test 4: Verify no separate add_reaction job exists