-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: validate new issues GHA #2190
Changes from 7 commits
48a124a
4eab05f
f52c621
3b6c2bf
a271df2
27e31ec
cba36bd
0367c8c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# | ||
# Copyright (c) 2023, salesforce.com, inc. | ||
# All rights reserved. | ||
# Licensed under the BSD 3-Clause license. | ||
# For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
# | ||
|
||
name: "Salesforce CLI Validate Issues" | ||
description: "Validate information provided in an new Github issue." | ||
author: "Eric Willhoit" | ||
inputs: | ||
repo-token: | ||
required: true | ||
description: "Token taken from secrets env var" | ||
runs: | ||
using: "node16" | ||
main: "index.js" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
const { getInput, setOutput, setFailed } = require("@actions/core"); | ||
const { context, getOctokit } = require("@actions/github"); | ||
const execSync = require("child_process").execSync; | ||
const semver = require("semver"); | ||
|
||
async function run() { | ||
try { | ||
// Set this env var to true to test locally | ||
// Example: GHA_VALIDATE_ISSUE_LOCAL=true node .github/actions/validate-issue/index.js | ||
const local = process.env.GHA_VALIDATE_ISSUE_LOCAL; | ||
const issue = local ? JSON.parse(getFile("./sample-context.json")) : context.payload.issue; | ||
|
||
if (!issue) { | ||
setFailed("github.context.payload.issue does not exist"); | ||
return; | ||
} | ||
|
||
const token = local ? process.env.GH_TOKEN : getInput("repo-token"); | ||
|
||
// Create a GitHub client | ||
const octokit = getOctokit(token); | ||
|
||
// Get owner and repo from context | ||
if (local) process.env.GITHUB_REPOSITORY = "iowillhoit/gha-sandbox"; | ||
const owner = context.repo.owner; | ||
const repo = context.repo.repo; | ||
const issue_number = issue.number; | ||
|
||
console.log("Issue URL:", issue.html_url); | ||
|
||
const { body } = issue; | ||
const { login: author } = issue.user; | ||
const { data: comments } = await getAllComments(); | ||
|
||
// For version checks, we only care about comments from the author | ||
const authorComments = comments.filter((comment) => comment.user.login === author); | ||
// Build an array of the issue body and all of the comment bodies | ||
const bodies = [body, ...authorComments.map((comment) => comment.body)]; | ||
|
||
const sfVersionRegex = /@salesforce\/cli\/([0-9]+.[0-9]+.[0-9]+(-[a-zA-Z0-9]+.[0-9]+)?)/g; | ||
const sfdxVersionRegex = /sfdx-cli\/([0-9]+.[0-9]+.[0-9]+(-[a-zA-Z0-9]+.[0-9]+)?)/g; | ||
const pluginVersionsRegex = /pluginVersions|Plugin Version:/; | ||
|
||
// Search all bodies and get an array of all versions found (first capture group) | ||
const sfVersions = bodies.map((body) => [...body.matchAll(sfVersionRegex)].map((match) => match[1])).flat(); | ||
const sfdxVersions = bodies.map((body) => [...body.matchAll(sfdxVersionRegex)].map((match) => match[1])).flat(); | ||
// If we match pluginVersionRegex anywhere, we assume the user has provided the full --verbose output | ||
const pluginVersionsIncluded = bodies.some((body) => body.match(pluginVersionsRegex)); | ||
|
||
console.log("sfVersions", sfVersions); | ||
console.log("sfdxVersions", sfdxVersions); | ||
console.log("pluginVersionsIncluded", pluginVersionsIncluded); | ||
|
||
if ((sfVersions.length > 0 || sfdxVersions.length > 0) && pluginVersionsIncluded) { | ||
// FUTURE TODO: | ||
// - Check for bundled plugins that are user installed (user) or linked (link) | ||
// - Could do a check to see if the users has a prerelease version installed | ||
let valid = true; | ||
|
||
if (sfVersions.length > 0) { | ||
const sfLatest = getLatestVersion("@salesforce/cli"); | ||
const oneSatisfies = sfVersions.some((version) => semver.gte(version, sfLatest)); | ||
|
||
if (!oneSatisfies) { | ||
const oldSf = getFile("./messages/old-cli.md", { THE_AUTHOR: author, USER_CLI: "sf", USER_VERSION: sfVersions.join("`, `"), LATEST_VERSION: sfLatest }); | ||
postComment(oldSf); | ||
valid = false; | ||
} | ||
} | ||
if (sfdxVersions.length > 0) { | ||
// TODO: Eventually suggest using sf@v2, a new md template could be created | ||
const sfdxLatest = getLatestVersion("sfdx-cli"); | ||
const oneSatisfies = sfdxVersions.some((version) => semver.gte(version, sfdxLatest)); | ||
|
||
if (!oneSatisfies) { | ||
const oldSfdx = getFile("./messages/old-cli.md", { THE_AUTHOR: author, USER_CLI: "sfdx", USER_VERSION: sfdxVersions.join("`, `"), LATEST_VERSION: sfdxLatest }); | ||
postComment(oldSfdx); | ||
valid = false; | ||
} | ||
} | ||
|
||
if (valid) { | ||
console.log("All information provided is valid!"); | ||
removeLabel("more information needed"); | ||
addLabel("investigating"); | ||
// This label will prevent the action from running again after version info has been confirmed | ||
// Otherwise, this action will continue to trigger after every weekly release as `latest` is bumped | ||
addLabel("validated"); | ||
} else { | ||
console.log("Information provided is NOT valid"); | ||
addLabel("more information needed"); | ||
removeLabel("investigating"); | ||
} | ||
} else { | ||
console.log("Full version information was not provided"); | ||
const message = getFile("./messages/provide-version.md", { THE_AUTHOR: issue.user.login }); | ||
postComment(message); | ||
addLabel("more information needed"); | ||
removeLabel("investigating"); | ||
} | ||
|
||
// --------- | ||
// FUNCTIONS | ||
// --------- | ||
async function getAllComments() { | ||
return await octokit.rest.issues.listComments({ owner, repo, issue_number }); | ||
} | ||
|
||
async function postComment(body) { | ||
// Check that this comment has not been previously commented | ||
if (comments.length) { | ||
if (comments.some((comment) => comment.body === body)) { | ||
console.log("Already commented"); | ||
return; | ||
} | ||
} | ||
|
||
return await octokit.rest.issues.createComment({ owner, repo, issue_number, body }); | ||
} | ||
|
||
async function addLabel(label) { | ||
await octokit.rest.issues.addLabels({ owner, repo, issue_number, labels: [label] }); | ||
} | ||
|
||
async function removeLabel(label) { | ||
try { | ||
await octokit.rest.issues.removeLabel({ owner, repo, issue_number, name: label }); | ||
} catch (error) { | ||
if (error.status === 404) { | ||
console.log(`Cannot remove label '${label}' since it was not applied`); | ||
return; | ||
} | ||
throw error; | ||
} | ||
} | ||
|
||
function getLatestVersion(plugin) { | ||
const distTags = execSync(`npm view ${plugin} dist-tags --json`).toString(); | ||
return JSON.parse(distTags).latest; | ||
} | ||
|
||
function getFile(filename, replacements) { | ||
let contents = fs.readFileSync(path.join(__dirname, filename), "utf8"); | ||
|
||
Object.entries(replacements || {}).map(([key, value]) => { | ||
contents = contents.replaceAll(key, value); | ||
}); | ||
|
||
return contents; | ||
} | ||
} catch (error) { | ||
setFailed(error.message); | ||
} | ||
} | ||
|
||
run(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
Hello @THE_AUTHOR :wave: None of the versions of `USER_CLI` you shared match the latest release. | ||
|
||
Shared: `USER_VERSION` | ||
Latest: `LATEST_VERSION` | ||
|
||
Update to the latest version of Salesforce CLI ([docs](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_update_cli.htm)) and confirm that you're still seeing your issue. | ||
You can also try the `rc` and `nightly` releases! ([docs](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli_rc.htm)) | ||
|
||
After updating, share the full output of `USER_CLI version --verbose --json` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
Hello @THE_AUTHOR :wave: It looks like you didn't include the full Salesforce CLI version information in your issue. | ||
Please provide the output of `version --verbose --json` for the CLI you're using (`sf` or `sfdx`). | ||
|
||
A few more things to check: | ||
|
||
- Make sure you've provided detailed steps to reproduce your issue. | ||
- A repository that clearly demonstrates the bug is ideal. | ||
- Make sure you've installed the latest version of Salesforce CLI. ([docs](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_update_cli.htm)) | ||
- Better yet, try the `rc` or `nightly` versions. ([docs](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli_rc.htm)) | ||
- Try running the `doctor` command to diagnose common issues. | ||
- Search GitHub for existing related issues. | ||
|
||
Thank you! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
{ | ||
"active_lock_reason": null, | ||
"assignee": null, | ||
"assignees": [], | ||
"author_association": "OWNER", | ||
"body": "@salesforce/cli/1.60.5 sfdx-cli/7.204.6 darwin-arm64 node-v18.15.0 pluginVersions", | ||
"closed_at": null, | ||
"comments": 0, | ||
"comments_url": "https://api.github.com/repos/iowillhoit/gha-sandbox/issues/16/comments", | ||
"created_at": "2023-06-06T21:03:32Z", | ||
"events_url": "https://api.github.com/repos/iowillhoit/gha-sandbox/issues/16/events", | ||
"html_url": "https://github.com/iowillhoit/gha-sandbox/issues/16", | ||
"id": 1744609461, | ||
"labels": [ | ||
{ | ||
"color": "FBCA04", | ||
"default": false, | ||
"description": "", | ||
"id": 5589614072, | ||
"name": "investigating", | ||
"node_id": "LA_kwDOI7bi188AAAABTSq9-A", | ||
"url": "https://api.github.com/repos/iowillhoit/gha-sandbox/labels/investigating" | ||
} | ||
], | ||
"labels_url": "https://api.github.com/repos/iowillhoit/gha-sandbox/issues/16/labels{/name}", | ||
"locked": false, | ||
"milestone": null, | ||
"node_id": "I_kwDOI7bi185n_KC1", | ||
"number": 16, | ||
"performed_via_github_app": null, | ||
"reactions": { | ||
"+1": 0, | ||
"-1": 0, | ||
"confused": 0, | ||
"eyes": 0, | ||
"heart": 0, | ||
"hooray": 0, | ||
"laugh": 0, | ||
"rocket": 0, | ||
"total_count": 0, | ||
"url": "https://api.github.com/repos/iowillhoit/gha-sandbox/issues/16/reactions" | ||
}, | ||
"repository_url": "https://api.github.com/repos/iowillhoit/gha-sandbox", | ||
"state": "open", | ||
"state_reason": null, | ||
"timeline_url": "https://api.github.com/repos/iowillhoit/gha-sandbox/issues/16/timeline", | ||
"title": "Test", | ||
"updated_at": "2023-06-06T21:49:50Z", | ||
"url": "https://api.github.com/repos/iowillhoit/gha-sandbox/issues/16", | ||
"user": { | ||
"avatar_url": "https://avatars.githubusercontent.com/u/1715111?v=4", | ||
"events_url": "https://api.github.com/users/iowillhoit/events{/privacy}", | ||
"followers_url": "https://api.github.com/users/iowillhoit/followers", | ||
"following_url": "https://api.github.com/users/iowillhoit/following{/other_user}", | ||
"gists_url": "https://api.github.com/users/iowillhoit/gists{/gist_id}", | ||
"gravatar_id": "", | ||
"html_url": "https://github.com/iowillhoit", | ||
"id": 1715111, | ||
"login": "iowillhoit", | ||
"node_id": "MDQ6VXNlcjE3MTUxMTE=", | ||
"organizations_url": "https://api.github.com/users/iowillhoit/orgs", | ||
"received_events_url": "https://api.github.com/users/iowillhoit/received_events", | ||
"repos_url": "https://api.github.com/users/iowillhoit/repos", | ||
"site_admin": false, | ||
"starred_url": "https://api.github.com/users/iowillhoit/starred{/owner}{/repo}", | ||
"subscriptions_url": "https://api.github.com/users/iowillhoit/subscriptions", | ||
"type": "User", | ||
"url": "https://api.github.com/users/iowillhoit" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# | ||
# Copyright (c) 2021, salesforce.com, inc. | ||
# All rights reserved. | ||
# Licensed under the BSD 3-Clause license. | ||
# For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause | ||
# | ||
|
||
name: "validate-updated-issue" | ||
on: | ||
issues: | ||
types: [edited] | ||
issue_comment: | ||
types: [created, edited] | ||
|
||
jobs: | ||
validate-issue: | ||
# Has label: 'more information needed' | ||
# Does NOT have labels: | ||
# - 'validated' | ||
# - 'investigating' | ||
# - 'feature' | ||
# - 'owned by another team' | ||
# - 'bug' | ||
if: contains(github.event.issue.labels.*.name, 'more information needed') && !contains(github.event.issue.labels.*.name, 'validated') && !contains(github.event.issue.labels.*.name, 'investigating') && !contains(github.event.issue.labels.*.name, 'feature') && !contains(github.event.issue.labels.*.name, 'owned by another team') && !contains(github.event.issue.labels.*.name, 'bug') | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3.0.0 | ||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: lts/* | ||
- name: Install dependencies | ||
run: yarn install | ||
- name: Validate issue | ||
id: validate-issue | ||
uses: ./.github/actions/validate-issue | ||
with: | ||
repo-token: ${{ secrets.GITHUB_TOKEN}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,21 @@ jobs: | |
If you require immediate assistance, contact Salesforce Customer Support. | ||
- name: log action output | ||
run: echo ${{steps.run_action.outputs.message}} | ||
validate-new-issue: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if I get your auto-response [say I forgot to put my version stuf], and then I modify the issue to include that, will this rerun? I'm thinking no because it's triggered off of new labels. We'd probably want it to "maintain" the Maybe it should be triggered by something else (create/edit of an issue ?) |
||
if: ${{ github.event.label.name == 'investigating' }} | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3.0.0 | ||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: lts/* | ||
- name: Install dependencies | ||
run: yarn install | ||
- name: Validate issue | ||
id: validate-issue | ||
uses: ./.github/actions/validate-issue | ||
with: | ||
repo-token: ${{ secrets.GITHUB_TOKEN}} | ||
new-feature: | ||
if: ${{ github.event.label.name == 'feature' && !contains(github.event.issue.labels.*.name, 'owned by another team') }} | ||
runs-on: ubuntu-latest | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd go higher since 16 is EOL in October.
I couldn't tell from the docs if there's a way to specify lts, but that would be best.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not supported yet 😑 actions/runner-images#7002 (comment)
I tried a work around there but it did not seem to work. Going to wait it out and hopefully they will add support