Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/add-pr-to-devops.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Add PR to DevOps Board

on:
pull_request:
types: [opened, reopened]
branches: [main, master]

jobs:
add_to_project:
runs-on: ubuntu-latest
if: |
github.event.pull_request.base.ref == 'main' ||
github.event.pull_request.base.ref == 'master'
permissions:
contents: read
pull-requests: write
repository-projects: write
organization-projects: write
steps:
- name: Add PR to DevOps Release Board
uses: actions/add-to-project@v0.5.0
with:
project-url: https://github.com/orgs/dhwani-ris/projects/##
github-token: ${{ secrets.GITHUB_TOKEN }}

7 changes: 4 additions & 3 deletions .github/workflows/auto-reviewer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ name: Auto Request Review

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
types: [opened, synchronize, reopened, ready_for_review, closed]
branches: [master]

permissions:
pull-requests: write
Expand All @@ -13,8 +14,8 @@ jobs:
name: Request Review from Default Reviewer
runs-on: ubuntu-latest
if: |
github.event.pull_request.base.ref == 'main' ||
github.event.pull_request.base.ref == 'master'
(github.event.action == 'opened' || github.event.action == 'reopened' || github.event.action == 'synchronize' || github.event.action == 'ready_for_review') &&
(github.event.pull_request.base.ref == 'main' || github.event.pull_request.base.ref == 'master')

steps:
- name: Request review from default reviewer
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/bot-handler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ on:
issue_comment:
types: [created, edited]
pull_request:
types: [opened, synchronize, reopened]
types: [opened, synchronize, reopened, closed]
branches: [master]

permissions:
contents: write
Expand Down
327 changes: 327 additions & 0 deletions .github/workflows/devops-checklist-submit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@
name: DevOps Checklist Submission

on:
issue_comment:
types: [created, edited]
pull_request:
types: [synchronize, reopened, ready_for_review, closed]

permissions:
pull-requests: write
contents: read

jobs:
submit-checklist:
runs-on: ubuntu-latest
if: |
(github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '/submit-checklist')) ||
(github.event_name == 'pull_request' && (github.event.action == 'synchronize' || github.event.action == 'reopened' || github.event.action == 'ready_for_review' || github.event.action == 'closed'))
steps:
- name: Get PR number
id: get-pr
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.payload.issue.number;
core.setOutput('pr_number', prNumber);
return prNumber;

- name: Submit and lock checklist
if: github.event_name == 'issue_comment' && contains(github.event.comment.body, '/submit-checklist')
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = context.payload.issue.number;
const submitter = context.payload.comment.user.login;
const submitTime = new Date().toISOString();
const submitDate = new Date().toLocaleString('en-US', {
timeZone: 'UTC',
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
timeZoneName: 'short'
});

// Get all comments to find the checklist
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});

const checklistComment = comments.data.find(
comment => comment.user.type === 'Bot' &&
comment.body.includes('DevOps Checklist - Workflow Review')
);

if (!checklistComment) {
console.log('Checklist comment not found');
return;
}

// Check if already submitted
if (checklistComment.body.includes('✅ **CHECKLIST SUBMITTED**')) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `⚠️ This checklist has already been submitted and cannot be modified.`
});
return;
}

// Extract the current checklist content (preserve checkboxes)
let checklistBody = checklistComment.body;

// Extract submission info to preserve it
const submissionInfo = `**Submitted by:** @${submitter}
**Submitted at:** ${submitDate} (UTC)`;

// Replace the submission section with submitted status
const submittedSection = `---

### ✅ **CHECKLIST SUBMITTED**

${submissionInfo}

🔒 **This checklist is now locked and cannot be modified.**

<!-- CHECKLIST_SUBMITTED_LOCK -->

---
**Note:** This checklist was submitted and is final. No further changes can be made.`;

// Find and replace the submission section
// Look for the "Submit Checklist" section and replace everything from there to the end
const submitSectionStart = checklistBody.indexOf('### 📤 Submit Checklist');
if (submitSectionStart !== -1) {
// Keep everything before the submission section, then add the submitted section
checklistBody = checklistBody.substring(0, submitSectionStart) + submittedSection;
} else {
// If section not found, append the submitted section
checklistBody = checklistBody + '\n\n' + submittedSection;
}

// Extract and store the exact checkbox states before locking
const checkboxStates = [];
const checkboxRegex = /- \[([ x])\] (.+)/g;
let match;
while ((match = checkboxRegex.exec(checklistBody)) !== null) {
checkboxStates.push({
checked: match[1] === 'x',
text: match[2]
});
}

// Store checkbox states in a hidden comment for restoration
const checkboxStatesJson = JSON.stringify(checkboxStates);

// Update the checklist comment to show it's submitted
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: checklistComment.id,
body: checklistBody
});

// Add a hidden comment with checkbox states for restoration
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `<!-- CHECKLIST_STATES:${checkboxStatesJson} -->`
});

// Add label to track submission
try {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: ['devops-checklist-submitted']
});
} catch (e) {
// Label might not exist, create it
try {
await github.rest.issues.createLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: 'devops-checklist-submitted',
color: '28a745',
description: 'DevOps Checklist has been submitted and locked'
});
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: ['devops-checklist-submitted']
});
} catch (labelError) {
console.log('Could not create/add label:', labelError.message);
}
}

// Add a confirmation comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `✅ **Checklist submitted successfully!**

The DevOps Checklist has been locked and cannot be modified.

**Submitted by:** @${submitter}
**Time:** ${submitDate} (UTC)`
});

console.log(`Checklist submitted by ${submitter} at ${submitTime}`);

- name: Re-lock checklist if edited after submission
if: |
(github.event_name == 'issue_comment' && github.event.action == 'edited') ||
(github.event_name == 'pull_request')
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const prNumber = github.event_name == 'issue_comment'
? context.payload.issue.number
: context.payload.pull_request.number;

// Get all comments to find the checklist
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});

const checklistComment = comments.data.find(
comment => comment.user.type === 'Bot' &&
comment.body.includes('DevOps Checklist - Workflow Review')
);

if (!checklistComment) {
return;
}

// Check if checklist was previously submitted (look for submission marker)
const hasSubmissionMarker = checklistComment.body.includes('CHECKLIST_SUBMITTED_LOCK');
const hasSubmittedText = checklistComment.body.includes('✅ **CHECKLIST SUBMITTED**');

// If it was submitted, ensure it's locked and restore checkbox states
if (hasSubmissionMarker || hasSubmittedText) {
let checklistBody = checklistComment.body;

// Get stored checkbox states from hidden comment
let storedStates = null;
const allComments = comments.data;
for (const comment of allComments) {
if (comment.body.includes('CHECKLIST_STATES:')) {
const statesMatch = comment.body.match(/CHECKLIST_STATES:(.+)/);
if (statesMatch) {
try {
storedStates = JSON.parse(statesMatch[1]);
break;
} catch (e) {
console.log('Could not parse stored states');
}
}
}
}

// Extract submission info
const submitterMatch = checklistBody.match(/\*\*Submitted by:\*\* @(\S+)/);
const dateMatch = checklistBody.match(/\*\*Submitted at:\*\* (.+?)(?:\n|UTC)/);
const submitter = submitterMatch ? submitterMatch[1] : 'System';
const submitDate = dateMatch ? dateMatch[1].trim() : new Date().toLocaleString('en-US', {
timeZone: 'UTC',
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
timeZoneName: 'short'
});

// Restore checkbox states if we have stored states
if (storedStates && storedStates.length > 0) {
let restoredBody = checklistBody;
const checkboxRegex = /- \[([ x])\] (.+)/g;
let stateIndex = 0;

restoredBody = restoredBody.replace(checkboxRegex, (match, checked, text) => {
if (stateIndex < storedStates.length) {
const state = storedStates[stateIndex];
stateIndex++;
// Restore the original checkbox state
return `- [${state.checked ? 'x' : ' '}] ${state.text}`;
}
return match;
});

checklistBody = restoredBody;
}

// Check if lock section is present and complete
const hasLockMessage = checklistBody.includes('🔒 **This checklist is now locked and cannot be modified.**');
const hasCompleteLock = hasSubmittedText && hasLockMessage;

// If lock is missing or incomplete, or checkboxes were changed, restore it
if (!hasCompleteLock || (storedStates && checklistBody !== checklistComment.body)) {
// Find where to insert/update the lock section
const submitIndex = checklistBody.indexOf('### ✅ **CHECKLIST SUBMITTED**');
const lockSection = `---

### ✅ **CHECKLIST SUBMITTED**

**Submitted by:** @${submitter}
**Submitted at:** ${submitDate} (UTC)

🔒 **This checklist is now locked and cannot be modified.**

<!-- CHECKLIST_SUBMITTED_LOCK -->

---
**Note:** This checklist was submitted and is final. No further changes can be made.`;

if (submitIndex !== -1) {
// Replace from submission header to end of comment
const beforeSubmit = checklistBody.substring(0, submitIndex);
checklistBody = beforeSubmit + lockSection;
} else {
// Append lock section if submission header is missing
checklistBody = checklistBody + '\n\n' + lockSection;
}

// Re-lock the checklist with restored states
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: checklistComment.id,
body: checklistBody
});

// Add a warning comment only if this is an edit event (not PR sync)
if (github.event_name == 'issue_comment' && github.event.action == 'edited') {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `⚠️ **Checklist Re-locked**

The DevOps Checklist was modified after submission. It has been automatically re-locked and restored to its submitted state.

🔒 **This checklist cannot be modified once submitted.**`
});
}

console.log('Checklist re-locked after unauthorized edit');
}
}

Loading
Loading