1+ /*
2+ activation_example:!release vancouver, !release latest flow, !release xanadu workspace
3+ regex:!release
4+ flags:gmi
5+ */
6+
7+ (function(current) {
8+ var input = current.text.replace(/!release/gmi, "").trim();
9+ var slacker = new x_snc_slackerbot.Slacker();
10+
11+ // Parse input to determine version and optional topic
12+ var parts = input.toLowerCase().split(/\s+/);
13+ var version = parts[0] || 'latest';
14+ var topic = parts.slice(1).join(' ');
15+
16+ // ServiceNow release version mapping
17+ var releaseMap = {
18+ 'latest': 'xanadu',
19+ 'xanadu': 'xanadu',
20+ 'washington': 'washington',
21+ 'vancouver': 'vancouver',
22+ 'utah': 'utah',
23+ 'tokyo': 'tokyo',
24+ 'sandiego': 'sandiego',
25+ 'rome': 'rome',
26+ 'quebec': 'quebec'
27+ };
28+
29+ var releaseName = releaseMap[version] || version;
30+
31+ // If no input provided, show help
32+ if (!input) {
33+ var helpMessage = '*ServiceNow Release Notes Helper* :books:\n\n' +
34+ '*Usage:*\n' +
35+ '• `!release <version>` - Get release notes for a specific version\n' +
36+ '• `!release latest` - Get latest release information\n' +
37+ '• `!release latest <topic>` - Search for a topic in latest release\n' +
38+ '• `!release <version> <topic>` - Search for a topic in specific version\n\n' +
39+ '*Supported Versions:*\n' +
40+ '`xanadu`, `washington`, `vancouver`, `utah`, `tokyo`, `sandiego`, `rome`, `quebec`\n\n' +
41+ '*Examples:*\n' +
42+ '• `!release vancouver` - Vancouver release notes\n' +
43+ '• `!release latest flow` - Search for "flow" in latest release\n' +
44+ '• `!release utah workspace` - Search for "workspace" in Utah release';
45+
46+ slacker.send_chat(current, helpMessage, false);
47+ return;
48+ }
49+
50+ // Build the base URL for ServiceNow docs
51+ var baseUrl = 'https://docs.servicenow.com';
52+ var releaseNotesUrl = baseUrl + '/bundle/' + releaseName + '-release-notes/page/release-notes.html';
53+
54+ // If topic is provided, use AI to search and summarize
55+ if (topic) {
56+ searchReleaseNotes(releaseName, topic, slacker, current);
57+ } else {
58+ // Just provide the release notes link and highlights
59+ getReleaseHighlights(releaseName, releaseNotesUrl, slacker, current);
60+ }
61+
62+ /**
63+ * Get release highlights for a specific version
64+ */
65+ function getReleaseHighlights(release, url, slacker, current) {
66+ // Fetch the release notes page
67+ var rm = new sn_ws.RESTMessageV2();
68+ rm.setHttpMethod('GET');
69+ rm.setEndpoint(url);
70+
71+ try {
72+ var response = rm.execute();
73+ var statusCode = response.getStatusCode();
74+
75+ if (statusCode === 200) {
76+ var body = response.getBody();
77+
78+ // Use AI to extract key highlights
79+ var chatReq = new sn_ws.RESTMessageV2();
80+ chatReq.setEndpoint('https://api.openai.com/v1/chat/completions');
81+ chatReq.setHttpMethod("POST");
82+ chatReq.setRequestHeader("Authorization", "Bearer " + gs.getProperty("openai.key"));
83+ chatReq.setRequestHeader('Content-Type', "application/json");
84+
85+ var aiBody = {
86+ "model": "gpt-4o-mini",
87+ "messages": [
88+ {
89+ "role": "system",
90+ "content": "You are a ServiceNow expert. Extract the top 5-7 key highlights from release notes. Format using Slack markdown with *bold* for feature names and bullet points. Keep it concise and developer-focused."
91+ },
92+ {
93+ "role": "user",
94+ "content": "Extract key highlights from this HTML (focus on new features, improvements, and breaking changes):\n\n" + body.substring(0, 15000)
95+ }
96+ ],
97+ "max_tokens": 500
98+ };
99+
100+ chatReq.setRequestBody(JSON.stringify(aiBody));
101+ var chatResponse = chatReq.execute();
102+ var chatBody = JSON.parse(chatResponse.getBody());
103+ var highlights = chatBody.choices[0].message.content;
104+
105+ var message = '*ServiceNow ' + release.charAt(0).toUpperCase() + release.slice(1) + ' Release Notes* :rocket:\n\n' +
106+ highlights + '\n\n' +
107+ ':link: <' + url + '|View Full Release Notes>';
108+
109+ slacker.send_chat(current, message, false);
110+ } else {
111+ // Fallback to direct link
112+ var fallbackMsg = '*ServiceNow ' + release.charAt(0).toUpperCase() + release.slice(1) + ' Release Notes* :books:\n\n' +
113+ ':link: <' + url + '|View Release Notes>\n\n' +
114+ '_Tip: Add a topic to search, e.g., `!release ' + release + ' flow`_';
115+
116+ slacker.send_chat(current, fallbackMsg, false);
117+ }
118+ } catch (e) {
119+ gs.error('Release Notes Parser Error: ' + e.message);
120+ var errorMsg = '*ServiceNow ' + release.charAt(0).toUpperCase() + release.slice(1) + ' Release Notes* :books:\n\n' +
121+ ':link: <' + url + '|View Release Notes>\n\n' +
122+ '_Tip: Add a topic to search, e.g., `!release ' + release + ' flow`_';
123+
124+ slacker.send_chat(current, errorMsg, false);
125+ }
126+ }
127+
128+ /**
129+ * Search for a specific topic in release notes
130+ */
131+ function searchReleaseNotes(release, topic, slacker, current) {
132+ var searchUrl = 'https://www.servicenow.com/docs/bundle/' + release + '-release-notes/page/release-notes.html';
133+
134+ // Fetch the release notes page
135+ var rm = new sn_ws.RESTMessageV2();
136+ rm.setHttpMethod('GET');
137+ rm.setEndpoint(searchUrl);
138+
139+ try {
140+ var response = rm.execute();
141+ var statusCode = response.getStatusCode();
142+
143+ if (statusCode === 200) {
144+ var body = response.getBody();
145+
146+ // Use AI to search for the topic
147+ var chatReq = new sn_ws.RESTMessageV2();
148+ chatReq.setEndpoint('https://api.openai.com/v1/chat/completions');
149+ chatReq.setHttpMethod("POST");
150+ chatReq.setRequestHeader("Authorization", "Bearer " + gs.getProperty("openai.key"));
151+ chatReq.setRequestHeader('Content-Type', "application/json");
152+
153+ var aiBody = {
154+ "model": "gpt-4o-mini",
155+ "messages": [
156+ {
157+ "role": "system",
158+ "content": "You are a ServiceNow expert. Search the release notes for information about the requested topic. Provide a concise summary with key points using Slack markdown (*bold*, bullet points). If the topic is not found, say so clearly."
159+ },
160+ {
161+ "role": "user",
162+ "content": "Search for information about '" + topic + "' in these release notes:\n\n" + body.substring(0, 15000)
163+ }
164+ ],
165+ "max_tokens": 600
166+ };
167+
168+ chatReq.setRequestBody(JSON.stringify(aiBody));
169+ var chatResponse = chatReq.execute();
170+ var chatBody = JSON.parse(chatResponse.getBody());
171+ var searchResults = chatBody.choices[0].message.content;
172+
173+ var message = '*ServiceNow ' + release.charAt(0).toUpperCase() + release.slice(1) + ' - "' + topic + '"* :mag:\n\n' +
174+ searchResults + '\n\n' +
175+ ':link: <' + searchUrl + '|View Full Release Notes>';
176+
177+ slacker.send_chat(current, message, false);
178+ } else {
179+ // Fallback to search link
180+ var encodedTopic = encodeURIComponent(topic);
181+ var fallbackUrl = 'https://www.servicenow.com/docs/search?q=' + encodedTopic + '&facetreset=yes&filter=bundle:' + release + '-release-notes';
182+
183+ var fallbackMsg = '*Searching for "' + topic + '" in ' + release.charAt(0).toUpperCase() + release.slice(1) + '* :mag:\n\n' +
184+ 'I couldn\'t fetch the release notes directly, but here\'s a search link:\n' +
185+ ':link: <' + fallbackUrl + '|Search Results for "' + topic + '">';
186+
187+ slacker.send_chat(current, fallbackMsg, false);
188+ }
189+ } catch (e) {
190+ gs.error('Release Notes Search Error: ' + e.message);
191+
192+ // Fallback to search link
193+ var encodedTopic = encodeURIComponent(topic);
194+ var fallbackUrl = 'https://www.servicenow.com/docs/search?q=' + encodedTopic + '&facetreset=yes&filter=bundle:' + release + '-release-notes';
195+
196+ var errorMsg = '*Searching for "' + topic + '" in ' + release.charAt(0).toUpperCase() + release.slice(1) + '* :mag:\n\n' +
197+ ':link: <' + fallbackUrl + '|Search Results for "' + topic + '">';
198+
199+ slacker.send_chat(current, errorMsg, false);
200+ }
201+ }
202+
203+ })(current);
0 commit comments