Skip to content

Commit 0f501a2

Browse files
authored
Merge branch 'main' into Highlight-Incident-Priority-Field
2 parents 4f9b979 + 48e315a commit 0f501a2

File tree

388 files changed

+14545
-591
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

388 files changed

+14545
-591
lines changed

.github/pull_request_template.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# PR Description:
2-
2+
replace this with your description
33

44
# Pull Request Checklist
55

66
## Overview
7+
- [x] Put an x inside of the square brackets to check each item.
78
- [ ] I have read and understood the [CONTRIBUTING.md](CONTRIBUTING.md) guidelines
8-
- [ ] My pull request has a descriptive title that accurately reflects the changes
9+
- [ ] My pull request has a descriptive title that accurately reflects the changes and the description has been filled in above.
910
- [ ] I've included only files relevant to the changes described in the PR title and description
1011
- [ ] I've created a new branch in my forked repository for this contribution
1112

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
name: Auto-unassign stale PR assignees
2+
3+
on:
4+
schedule:
5+
- cron: "*/15 * * * *" # run every 15 minutes
6+
workflow_dispatch:
7+
inputs:
8+
enabled:
9+
description: "Enable this automation"
10+
type: boolean
11+
default: true
12+
max_age_minutes:
13+
description: "Unassign if assigned longer than X minutes"
14+
type: number
15+
default: 60
16+
dry_run:
17+
description: "Preview only; do not change assignees"
18+
type: boolean
19+
default: false
20+
21+
permissions:
22+
pull-requests: write
23+
issues: write
24+
25+
env:
26+
# Defaults (can be overridden via workflow_dispatch inputs)
27+
ENABLED: "true"
28+
MAX_ASSIGN_AGE_MINUTES: "60"
29+
DRY_RUN: "false"
30+
31+
jobs:
32+
sweep:
33+
runs-on: ubuntu-latest
34+
steps:
35+
- name: Resolve inputs into env
36+
run: |
37+
# Prefer manual run inputs when present
38+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
39+
echo "ENABLED=${{ inputs.enabled }}" >> $GITHUB_ENV
40+
echo "MAX_ASSIGN_AGE_MINUTES=${{ inputs.max_age_minutes }}" >> $GITHUB_ENV
41+
echo "DRY_RUN=${{ inputs.dry_run }}" >> $GITHUB_ENV
42+
fi
43+
echo "Effective config: ENABLED=$ENABLED, MAX_ASSIGN_AGE_MINUTES=$MAX_ASSIGN_AGE_MINUTES, DRY_RUN=$DRY_RUN"
44+
45+
- name: Exit if disabled
46+
if: ${{ env.ENABLED != 'true' && env.ENABLED != 'True' && env.ENABLED != 'TRUE' }}
47+
run: echo "Disabled via ENABLED=$ENABLED. Exiting." && exit 0
48+
49+
- name: Unassign stale assignees
50+
uses: actions/github-script@v7
51+
with:
52+
script: |
53+
const owner = context.repo.owner;
54+
const repo = context.repo.repo;
55+
56+
const MAX_MIN = parseInt(process.env.MAX_ASSIGN_AGE_MINUTES || "60", 10);
57+
const DRY_RUN = ["true","True","TRUE","1","yes"].includes(String(process.env.DRY_RUN));
58+
const now = new Date();
59+
60+
core.info(`Scanning open PRs. Threshold = ${MAX_MIN} minutes. DRY_RUN=${DRY_RUN}`);
61+
62+
// List all open PRs
63+
const prs = await github.paginate(github.rest.pulls.list, {
64+
owner, repo, state: "open", per_page: 100
65+
});
66+
67+
let totalUnassigned = 0;
68+
69+
for (const pr of prs) {
70+
if (!pr.assignees || pr.assignees.length === 0) continue;
71+
72+
const number = pr.number;
73+
core.info(`PR #${number}: "${pr.title}" — assignees: ${pr.assignees.map(a => a.login).join(", ")}`);
74+
75+
// Pull reviews (to see if an assignee started a review)
76+
const reviews = await github.paginate(github.rest.pulls.listReviews, {
77+
owner, repo, pull_number: number, per_page: 100
78+
});
79+
80+
// Issue comments (general comments)
81+
const issueComments = await github.paginate(github.rest.issues.listComments, {
82+
owner, repo, issue_number: number, per_page: 100
83+
});
84+
85+
// Review comments (file-level)
86+
const reviewComments = await github.paginate(github.rest.pulls.listReviewComments, {
87+
owner, repo, pull_number: number, per_page: 100
88+
});
89+
90+
// Issue events (to find assignment timestamps)
91+
const issueEvents = await github.paginate(github.rest.issues.listEvents, {
92+
owner, repo, issue_number: number, per_page: 100
93+
});
94+
95+
for (const a of pr.assignees) {
96+
const assignee = a.login;
97+
98+
// Find the most recent "assigned" event for this assignee
99+
const assignedEvents = issueEvents
100+
.filter(e => e.event === "assigned" && e.assignee && e.assignee.login === assignee)
101+
.sort((x, y) => new Date(y.created_at) - new Date(x.created_at));
102+
103+
if (assignedEvents.length === 0) {
104+
core.info(` - @${assignee}: no 'assigned' event found; skipping.`);
105+
continue;
106+
}
107+
108+
const assignedAt = new Date(assignedEvents[0].created_at);
109+
const ageMin = (now - assignedAt) / 60000;
110+
111+
// Has the assignee commented (issue or review comments) or reviewed?
112+
const hasIssueComment = issueComments.some(c => c.user?.login === assignee);
113+
const hasReviewComment = reviewComments.some(c => c.user?.login === assignee);
114+
const hasReview = reviews.some(r => r.user?.login === assignee);
115+
116+
const eligible =
117+
ageMin >= MAX_MIN &&
118+
!hasIssueComment &&
119+
!hasReviewComment &&
120+
!hasReview &&
121+
pr.state === "open";
122+
123+
core.info(` - @${assignee}: assigned ${ageMin.toFixed(1)} min ago; commented=${hasIssueComment || hasReviewComment}; reviewed=${hasReview}; open=${pr.state==='open'} => ${eligible ? 'ELIGIBLE' : 'skip'}`);
124+
125+
if (!eligible) continue;
126+
127+
if (DRY_RUN) {
128+
core.notice(`Would unassign @${assignee} from PR #${number}`);
129+
} else {
130+
try {
131+
await github.rest.issues.removeAssignees({
132+
owner, repo, issue_number: number, assignees: [assignee]
133+
});
134+
totalUnassigned += 1;
135+
// Optional: leave a gentle heads-up comment
136+
await github.rest.issues.createComment({
137+
owner, repo, issue_number: number,
138+
body: `👋 Unassigning @${assignee} due to inactivity (> ${MAX_MIN} min without comments/reviews). This PR remains open for other reviewers.`
139+
});
140+
core.info(` Unassigned @${assignee} from #${number}`);
141+
} catch (err) {
142+
core.warning(` Failed to unassign @${assignee} from #${number}: ${err.message}`);
143+
}
144+
}
145+
}
146+
}
147+
148+
core.summary
149+
.addHeading('Auto-unassign report')
150+
.addRaw(`Threshold: ${MAX_MIN} minutes\n\n`)
151+
.addRaw(`Total unassignments: ${totalUnassigned}\n`)
152+
.write();
153+
154+
result-encoding: string

CONTRIBUTING.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,25 @@ If you plan to submit another pull request while your original is still pending,
3131
- **Descriptive Pull Request Titles**: Your pull request must have explicit and descriptive titles that accurately represent the changes made.
3232
- **Scope Adherence**: Changes that fall outside the described scope will result in the entire pull request being rejected.
3333
- **Quality Over Quantity**: Low-effort or spam pull requests will be marked accordingly.
34-
- **Expanded Snippets**: Code snippets reused from the [ServiceNow Documentation](https://docs.servicenow.com/) or [API References](https://developer.servicenow.com/dev.do#!/reference/) are acceptable only if they are expanded in a meaningful way (e.g., with additional context, documentation, or variations). Remember: *QUANTITY IS FUN, QUALITY IS KEY.*
34+
- **Expanded Snippets**: Code snippets reused from the [ServiceNow Documentation](https://docs.servicenow.com/) or [API References](https://developer.servicenow.com/dev.do#!/reference/) are acceptable only if they are expanded in a meaningful way (e.g., with additional context, documentation, or variations). Remember: *"QUANTITY IS FUN, QUALITY IS KEY."*
3535
- **Relevance**: Code should be relevant to ServiceNow Developers.
3636
- **ES2021 Compatibility**: While ES2021 is allowed, we encourage you to disclose if your code is using ES2021 features, as not everyone may be working with ES2021-enabled applications.
3737

38+
## Core Documentation File Changes
39+
40+
**IMPORTANT**: For changes to core documentation files (README.md, CONTRIBUTING.md, LICENSE, etc.), contributors must:
41+
42+
1. **Submit an Issue First**: Before making any changes to core documentation files, create an issue describing:
43+
- What you intend to edit
44+
- Why the change is needed
45+
- Your proposed approach
46+
47+
2. **Get Assignment**: Wait to be assigned to the issue by a maintainer before submitting a PR.
48+
49+
3. **Reference the Issue**: Include the issue number in your PR title and description.
50+
51+
This process helps prevent merge conflicts when multiple contributors want to update the same documentation files and ensures all changes align with the project's direction.
52+
3853
## Repository Structure
3954

4055
**IMPORTANT**: The repository has been reorganized into major categories. All new contributions MUST follow this structure for PR approval.
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Auto Save Draft Feature for Catalog Items
2+
3+
This snippet provides automatic draft saving functionality for ServiceNow Catalog Items, helping prevent data loss by automatically saving form data at regular intervals.
4+
5+
## Overview
6+
7+
The feature includes two implementations:
8+
1. Basic Implementation (`basic_implementation.js`)
9+
2. Advanced Implementation (`advanced_implementation.js`)
10+
11+
## Basic Implementation
12+
13+
### Features
14+
- Auto-saves form data every minute
15+
- Stores single draft in sessionStorage
16+
- Provides draft restoration on form load
17+
- Basic error handling and user feedback
18+
19+
### Usage
20+
```javascript
21+
// Apply in Catalog Client Script
22+
// Select "onLoad" for "Client script runs"
23+
// Copy content from basic_implementation.js
24+
```
25+
26+
## Advanced Implementation
27+
28+
### Enhanced Features
29+
- Multiple draft support (keeps last 3 drafts)
30+
- Advanced draft management
31+
- Draft selection dialog
32+
- Detailed metadata tracking
33+
- Improved error handling
34+
- User-friendly notifications
35+
36+
### Usage
37+
```javascript
38+
// Apply in Catalog Client Script
39+
// Select "onLoad" for "Client script runs"
40+
// Copy content from advanced_implementation.js
41+
```
42+
43+
## Technical Details
44+
45+
### Dependencies
46+
- ServiceNow Platform UI Framework
47+
- GlideForm API
48+
- GlideModal (advanced implementation only)
49+
50+
### Browser Support
51+
- Modern browsers with sessionStorage support
52+
- ES5+ compatible
53+
54+
### Security Considerations
55+
- Uses browser's sessionStorage (cleared on session end)
56+
- No sensitive data transmission
57+
- Instance-specific storage
58+
59+
## Implementation Guide
60+
61+
1. Create a new Catalog Client Script:
62+
- Table: Catalog Client Script [catalog_script_client]
63+
- Type: onLoad
64+
- Active: true
65+
66+
2. Choose implementation:
67+
- For basic needs: Copy `basic_implementation.js`
68+
- For advanced features: Copy `advanced_implementation.js`
69+
70+
3. Apply to desired Catalog Items:
71+
- Select applicable Catalog Items
72+
- Test in dev environment first
73+
74+
## Best Practices
75+
76+
1. Testing:
77+
- Test with various form states
78+
- Verify draft restoration
79+
- Check browser storage limits
80+
81+
2. Performance:
82+
- Default 60-second interval is recommended
83+
- Adjust based on form complexity
84+
- Monitor browser memory usage
85+
86+
3. User Experience:
87+
- Clear feedback messages
88+
- Confirmation dialogs
89+
- Error notifications
90+
91+
## Limitations
92+
93+
- Browser session dependent
94+
- Storage size limits
95+
- Form field compatibility varies
96+
97+
## Troubleshooting
98+
99+
Common issues and solutions:
100+
1. Draft not saving
101+
- Check browser console for errors
102+
- Verify sessionStorage availability
103+
- Check form modification detection
104+
105+
2. Restoration fails
106+
- Validate stored data format
107+
- Check browser storage permissions
108+
- Verify form field compatibility
109+
110+
## Version Information
111+
112+
- Compatible with ServiceNow: Rome and later
113+
- Browser Requirements: Modern browsers with ES5+ support
114+
- Last Updated: October 2025

0 commit comments

Comments
 (0)