diff --git a/script/application_test.go b/script/application_test.go
index 37191223..34e942f4 100644
--- a/script/application_test.go
+++ b/script/application_test.go
@@ -7,35 +7,35 @@ import (
)
func errNoProjectName(sectionTitle string) error {
- return fmt.Errorf("%s: is missing project name", sectionTitle)
+ return fmt.Errorf("**%s** is missing project name", sectionTitle)
}
func errIncomplete(sectionTitle string) error {
- return fmt.Errorf("%s: was not completed for application", sectionTitle)
+ return fmt.Errorf("**%s** was not completed for application", sectionTitle)
}
func errEmpty(sectionTitle string) error {
- return fmt.Errorf("%s: is empty", sectionTitle)
+ return fmt.Errorf("**%s** is empty", sectionTitle)
}
func errMustBeChecked(sectionTitle string) error {
- return fmt.Errorf("%s: must be checked", sectionTitle)
+ return fmt.Errorf("**%s** must be checked", sectionTitle)
}
func errInvalidAccountURL(sectionTitle string) error {
- return fmt.Errorf("%s: is invalid 1Password account URL", sectionTitle)
+ return fmt.Errorf("**%s** is invalid 1Password account URL", sectionTitle)
}
func errContainsEmoji(sectionTitle string) error {
- return fmt.Errorf("%s: cannot contain emoji characters", sectionTitle)
+ return fmt.Errorf("**%s** cannot contain emoji characters", sectionTitle)
}
func errParsingNumber(sectionTitle string) error {
- return fmt.Errorf("%s: could not be parsed into a number", sectionTitle)
+ return fmt.Errorf("**%s** could not be parsed into a number", sectionTitle)
}
func errInvalidURL(sectionTitle string) error {
- return fmt.Errorf("%s: is an invalid URL", sectionTitle)
+ return fmt.Errorf("**%s** is an invalid URL", sectionTitle)
}
func TestApplication(t *testing.T) {
@@ -71,6 +71,10 @@ func TestApplication(t *testing.T) {
name: "event",
expectedValid: true,
},
+ {
+ name: "project-character-test",
+ expectedValid: true,
+ },
{
name: "empty-body",
expectedValid: false,
diff --git a/script/reviewer.go b/script/reviewer.go
index 04c1371f..a47a1ebc 100644
--- a/script/reviewer.go
+++ b/script/reviewer.go
@@ -1,9 +1,19 @@
package main
import (
+ "fmt"
"log"
)
+type Status int
+
+const (
+ Approved Status = iota
+ Reviewing
+ Invalid
+ New
+)
+
type Reviewer struct {
gitHub GitHub
application Application
@@ -19,11 +29,99 @@ func (r *Reviewer) Review() {
r.application.Parse(r.gitHub.Issue)
- if isTestingIssue() {
- if r.application.IsValid() {
- debugMessage("Application has no problems")
+ status := r.getStatus()
+ isClosed := *r.gitHub.Issue.State == "closed"
+
+ r.updateLabels(status, isClosed)
+ r.createComment(status, isClosed)
+}
+
+func (r *Reviewer) getStatus() Status {
+ if r.gitHub.IssueHasLabel(LabelStatusApproved) {
+ return Approved
+ } else if r.gitHub.IssueHasLabel(LabelStatusReviewing) {
+ return Reviewing
+ } else if r.gitHub.IssueHasLabel(LabelStatusInvalid) {
+ return Invalid
+ } else {
+ return New
+ }
+}
+
+func (r *Reviewer) createComment(status Status, isClosed bool) {
+ title := ""
+ body := ""
+
+ applicationData := fmt.Sprintf("\nApplication data...
\n\n```json\n%s\n```\n ", r.application.GetData())
+ applicationFilePath := fmt.Sprintf("https://github.com/1Password/1password-teams-open-source/blob/main/data/%s", r.application.FileName())
+ approvedBody := fmt.Sprintf("This application has already been approved and changes will not be reviewed. If you would like to modify the details of your application, submit a pull request against the stored [application data](%s). If you have any questions, contact us at [opensource@1password.com](mailto:opensource@1password.com).", applicationFilePath)
+ closedBody := "This application is closed and changes will not be reviewed. If you have any questions, contact us at [opensource@1password.com](mailto:opensource@1password.com)."
+
+ // If the issue is closed, let the user know that they can't make changes.
+ // If the issue was closed because it got approved, let them know how they can
+ // modify their application details after the fact.
+ if isClosed {
+ if status == Approved {
+ body = approvedBody
+ } else {
+ body = closedBody
+ }
+ // This scanerio should never occur, as an approved issue should
+ // immediately be closed, but let's cover all bases.
+ } else if status == Approved {
+ body = approvedBody
+ } else if r.application.IsValid() {
+ if status == Reviewing {
+ title = "### π Application still valid"
+ body = fmt.Sprintf("\n\n%s\n\nWeβve run our automated pre-checks and your updated application is still valid.", applicationData)
} else {
- debugMessage("Application problems:", r.application.RenderProblems())
+ title = "### β
Your application is valid"
+ body = fmt.Sprintf("\n\n%s\n\nThanks for applying! Our automated pre-checks have determined your application is valid. Next step: our team will review your application and may have follow-up questions. You can still make changes to your application and itβll be re-evaluated.", applicationData)
+ }
+ } else {
+ title = "### β Your application is invalid"
+ body = fmt.Sprintf("\n\n%s\n\nOur automated pre-checks have detected the following problems:\n\n%s\n\nUpdate this issue to correct these problems and weβll automatically re-evaluate your application.", applicationData, r.application.RenderProblems())
+ }
+
+ r.gitHub.CreateIssueComment(fmt.Sprintf("%s%s", title, body))
+}
+
+func (r *Reviewer) updateLabels(status Status, isClosed bool) {
+ if status == Approved || isClosed {
+ return
+ }
+
+ if r.application.IsValid() {
+ if status == Invalid {
+ if err := r.gitHub.RemoveIssueLabel(LabelStatusInvalid); err != nil {
+ r.printErrorAndExit(
+ fmt.Errorf("could not remove issue label '%s': %s", LabelStatusInvalid, err.Error()),
+ )
+ }
+ }
+
+ if status != Reviewing {
+ if err := r.gitHub.AddIssueLabel(LabelStatusReviewing); err != nil {
+ r.printErrorAndExit(
+ fmt.Errorf("could not add issue label '%s': %s", LabelStatusReviewing, err.Error()),
+ )
+ }
+ }
+ } else {
+ if status != Invalid {
+ if err := r.gitHub.AddIssueLabel(LabelStatusInvalid); err != nil {
+ r.printErrorAndExit(
+ fmt.Errorf("could not add issue label '%s': %s", LabelStatusInvalid, err.Error()),
+ )
+ }
+ }
+
+ if status == Reviewing {
+ if err := r.gitHub.RemoveIssueLabel(LabelStatusReviewing); err != nil {
+ r.printErrorAndExit(
+ fmt.Errorf("could not remove issue label '%s': %s", LabelStatusReviewing, err.Error()),
+ )
+ }
}
}
}
diff --git a/script/test-issues/valid-project-approved-closed.json b/script/test-issues/valid-project-approved-closed.json
new file mode 100644
index 00000000..e8af7923
--- /dev/null
+++ b/script/test-issues/valid-project-approved-closed.json
@@ -0,0 +1,60 @@
+{
+ "id": 1801650328,
+ "number": 6,
+ "state": "closed",
+ "locked": false,
+ "title": "Application for TestDB",
+ "body": "### Account URL\n\ntestdb.1password.com\n\n### Non-commercial confirmation\n\n- [X] No, this account won't be used for commercial activity\n\n### Team application\n\n- [ ] Yes, this application is for a team\n\n### Event application\n\n- [ ] Yes, this application is for an event\n\n### Project name\n\nTestDB\n\n### Short description\n\nTestDB is a free and open source, community-based forum software project.\n\n### Number of team members/core contributors\n\n1\n\n### Homepage URL\n\nhttps://github.com/wendyappleed/test-db\n\n### Repository URL\n\nhttps://github.com/wendyappleed/test-db\n\n### License type\n\nMIT\n\n### License URL\n\nhttps://github.com/wendyappleed/test-db/blob/main/LICENSE.md\n\n### Age confirmation\n\n- [X] Yes, this project is at least 30 days old\n\n### Name\n\nWendy Appleseed\n\n### Email\n\nwendyappleseed@example.com\n\n### Project role\n\nCore Maintainer\n\n### Profile or website\n\nhttps://github.com/wendyappleseed/\n\n### Can we contact you?\n\n- [X] Yes, you may contact me\n\n### Additional comments\n\nThank you!",
+ "user": {
+ "login": "wendyappleseed",
+ "id": 38230737,
+ "node_id": "MDQ6VXNlcjYzOTIwNDk=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/38230737?v=4",
+ "html_url": "https://github.com/wendyappleseed",
+ "gravatar_id": "",
+ "type": "User",
+ "site_admin": false,
+ "url": "https://api.github.com/users/wendyappleseed",
+ "events_url": "https://api.github.com/users/wendyappleseed/events{/privacy}",
+ "following_url": "https://api.github.com/users/wendyappleseed/following{/other_user}",
+ "followers_url": "https://api.github.com/users/wendyappleseed/followers",
+ "gists_url": "https://api.github.com/users/wendyappleseed/gists{/gist_id}",
+ "organizations_url": "https://api.github.com/users/wendyappleseed/orgs",
+ "received_events_url": "https://api.github.com/users/wendyappleseed/received_events",
+ "repos_url": "https://api.github.com/users/wendyappleseed/repos",
+ "starred_url": "https://api.github.com/users/wendyappleseed/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/wendyappleseed/subscriptions"
+ },
+ "labels": [
+ {
+ "id": 5728067083,
+ "url": "https://api.github.com/repos/1Password/1password-teams-open-source/labels/status:%20approved",
+ "name": "status: approved",
+ "color": "0052CC",
+ "description": "The application has been approved",
+ "default": false,
+ "node_id": "LA_kwDOJ6JE6M8AAAABVWteCw"
+ }
+ ],
+ "comments": 11,
+ "closed_at": "2023-07-13T05:03:51Z",
+ "created_at": "2023-07-12T19:49:35Z",
+ "updated_at": "2023-07-13T05:03:51Z",
+ "url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6",
+ "html_url": "https://github.com/wendyappleseed/1password-teams-open-source/issues/6",
+ "comments_url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/comments",
+ "events_url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/events",
+ "labels_url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/labels{/name}",
+ "repository_url": "https://api.github.com/repos/1Password/1password-teams-open-source",
+ "reactions": {
+ "total_count": 0,
+ "+1": 0,
+ "-1": 0,
+ "laugh": 0,
+ "confused": 0,
+ "heart": 0,
+ "hooray": 0,
+ "url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/reactions"
+ },
+ "node_id": "I_kwDOJ6JE6M5rYwCY"
+}
diff --git a/script/test-issues/valid-project-character-test.json b/script/test-issues/valid-project-character-test.json
new file mode 100644
index 00000000..59363858
--- /dev/null
+++ b/script/test-issues/valid-project-character-test.json
@@ -0,0 +1,49 @@
+{
+ "id": 1801650328,
+ "number": 6,
+ "state": "open",
+ "locked": false,
+ "title": "Application for TestDB",
+ "body": "### Account URL\n\n`testdb.1password.com`\n\n### Non-commercial confirmation\n\n- [X] No, this account won't be used for commercial activity\n\n### π¨βπ» Team application\n\n- [X] Yes, this application is for a team\n\n### Event application\n\n- [ ] Yes, this application is for an event\n\n### Project name\n\n`_TestDB_\n\n- test``\n\n### Short description\n\nTestDB is a free and open source, community-based forum software project.```\n\n## **This is a test comment**
\n\n### Number of team members/core contributors\n\n1\n\n### Homepage URL\n\nhttps://github.com/wendyappleed/test-db\n\n### Repository URL\n\nhttps://github.com/wendyappleed/test-db\n\n### License type\n\nMIT\n\n### License URL\n\nhttps://github.com/wendyappleed/test-db/blob/main/LICENSE.md\n\n### Age confirmation\n\n- [X] Yes, this project is at least 30 days old\n\n### Name\n\nWendy Appleseed\n\n### Email\n\nwendyappleseed@example.com\n\n### Project role\n\nCore Maintainer\n\n### Profile or website\n\nhttps://github.com/wendyappleseed/\n\n### Can we contact you?\n\n- [X] Yes, you may contact me\n\n### Additional comments\n\n Thank you!",
+ "user": {
+ "login": "wendyappleseed",
+ "id": 38230737,
+ "node_id": "MDQ6VXNlcjYzOTIwNDk=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/38230737?v=4",
+ "html_url": "https://github.com/wendyappleseed",
+ "gravatar_id": "",
+ "type": "User",
+ "site_admin": false,
+ "url": "https://api.github.com/users/wendyappleseed",
+ "events_url": "https://api.github.com/users/wendyappleseed/events{/privacy}",
+ "following_url": "https://api.github.com/users/wendyappleseed/following{/other_user}",
+ "followers_url": "https://api.github.com/users/wendyappleseed/followers",
+ "gists_url": "https://api.github.com/users/wendyappleseed/gists{/gist_id}",
+ "organizations_url": "https://api.github.com/users/wendyappleseed/orgs",
+ "received_events_url": "https://api.github.com/users/wendyappleseed/received_events",
+ "repos_url": "https://api.github.com/users/wendyappleseed/repos",
+ "starred_url": "https://api.github.com/users/wendyappleseed/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/wendyappleseed/subscriptions"
+ },
+ "comments": 11,
+ "closed_at": "2023-07-13T05:03:51Z",
+ "created_at": "2023-07-12T19:49:35Z",
+ "updated_at": "2023-07-13T05:03:51Z",
+ "url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6",
+ "html_url": "https://github.com/wendyappleseed/1password-teams-open-source/issues/6",
+ "comments_url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/comments",
+ "events_url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/events",
+ "labels_url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/labels{/name}",
+ "repository_url": "https://api.github.com/repos/1Password/1password-teams-open-source",
+ "reactions": {
+ "total_count": 0,
+ "+1": 0,
+ "-1": 0,
+ "laugh": 0,
+ "confused": 0,
+ "heart": 0,
+ "hooray": 0,
+ "url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/reactions"
+ },
+ "node_id": "I_kwDOJ6JE6M5rYwCY"
+}
diff --git a/script/test-issues/valid-project-reviewing.json b/script/test-issues/valid-project-reviewing.json
new file mode 100644
index 00000000..80042b67
--- /dev/null
+++ b/script/test-issues/valid-project-reviewing.json
@@ -0,0 +1,60 @@
+{
+ "id": 1801650328,
+ "number": 6,
+ "state": "open",
+ "locked": false,
+ "title": "Application for TestDB",
+ "body": "### Account URL\n\ntestdb.1password.com\n\n### Non-commercial confirmation\n\n- [X] No, this account won't be used for commercial activity\n\n### Team application\n\n- [ ] Yes, this application is for a team\n\n### Event application\n\n- [ ] Yes, this application is for an event\n\n### Project name\n\nTestDB\n\n### Short description\n\nTestDB is a free and open source, community-based forum software project.\n\n### Number of team members/core contributors\n\n1\n\n### Homepage URL\n\nhttps://github.com/wendyappleed/test-db\n\n### Repository URL\n\nhttps://github.com/wendyappleed/test-db\n\n### License type\n\nMIT\n\n### License URL\n\nhttps://github.com/wendyappleed/test-db/blob/main/LICENSE.md\n\n### Age confirmation\n\n- [X] Yes, this project is at least 30 days old\n\n### Name\n\nWendy Appleseed\n\n### Email\n\nwendyappleseed@example.com\n\n### Project role\n\nCore Maintainer\n\n### Profile or website\n\nhttps://github.com/wendyappleseed/\n\n### Can we contact you?\n\n- [X] Yes, you may contact me\n\n### Additional comments\n\nThank you!",
+ "user": {
+ "login": "wendyappleseed",
+ "id": 38230737,
+ "node_id": "MDQ6VXNlcjYzOTIwNDk=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/38230737?v=4",
+ "html_url": "https://github.com/wendyappleseed",
+ "gravatar_id": "",
+ "type": "User",
+ "site_admin": false,
+ "url": "https://api.github.com/users/wendyappleseed",
+ "events_url": "https://api.github.com/users/wendyappleseed/events{/privacy}",
+ "following_url": "https://api.github.com/users/wendyappleseed/following{/other_user}",
+ "followers_url": "https://api.github.com/users/wendyappleseed/followers",
+ "gists_url": "https://api.github.com/users/wendyappleseed/gists{/gist_id}",
+ "organizations_url": "https://api.github.com/users/wendyappleseed/orgs",
+ "received_events_url": "https://api.github.com/users/wendyappleseed/received_events",
+ "repos_url": "https://api.github.com/users/wendyappleseed/repos",
+ "starred_url": "https://api.github.com/users/wendyappleseed/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/wendyappleseed/subscriptions"
+ },
+ "labels": [
+ {
+ "id": 5728067083,
+ "url": "https://api.github.com/repos/1Password/1password-teams-open-source/labels/status:%20reviewing",
+ "name": "status: reviewing",
+ "color": "0052CC",
+ "description": "The application is being reviewed",
+ "default": false,
+ "node_id": "LA_kwDOJ6JE6M8AAAABVWteCw"
+ }
+ ],
+ "comments": 11,
+ "closed_at": "2023-07-13T05:03:51Z",
+ "created_at": "2023-07-12T19:49:35Z",
+ "updated_at": "2023-07-13T05:03:51Z",
+ "url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6",
+ "html_url": "https://github.com/wendyappleseed/1password-teams-open-source/issues/6",
+ "comments_url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/comments",
+ "events_url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/events",
+ "labels_url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/labels{/name}",
+ "repository_url": "https://api.github.com/repos/1Password/1password-teams-open-source",
+ "reactions": {
+ "total_count": 0,
+ "+1": 0,
+ "-1": 0,
+ "laugh": 0,
+ "confused": 0,
+ "heart": 0,
+ "hooray": 0,
+ "url": "https://api.github.com/repos/1Password/1password-teams-open-source/issues/6/reactions"
+ },
+ "node_id": "I_kwDOJ6JE6M5rYwCY"
+}
diff --git a/script/validator.go b/script/validator.go
index 9dcd247b..b783a858 100644
--- a/script/validator.go
+++ b/script/validator.go
@@ -30,7 +30,7 @@ type ValidationError struct {
type ValidatorCallback func(string) (bool, string, string)
func (e *ValidationError) Error() string {
- return fmt.Sprintf("%s: %s", e.Section, e.Message)
+ return fmt.Sprintf("**%s** %s", e.Section, e.Message)
}
type Validator struct {
@@ -69,11 +69,7 @@ func ParseInput(value string) (bool, string, string) {
return true, "", ""
}
- return true, value, ""
-}
-
-func ParsePlainString(value string) (bool, string, string) {
- // strip all formattig, except for newlines
+ // strip all formatting, except for newlines
html := blackfriday.Run([]byte(value))
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(html))
if err != nil {
@@ -81,6 +77,10 @@ func ParsePlainString(value string) (bool, string, string) {
}
value = strings.TrimSpace(doc.Text())
+ return true, value, ""
+}
+
+func ParsePlainString(value string) (bool, string, string) {
if urlRegex.MatchString(value) {
return false, value, "cannot contain URLs"
}
diff --git a/script/validator_test.go b/script/validator_test.go
index 3a458240..cbeb9a65 100644
--- a/script/validator_test.go
+++ b/script/validator_test.go
@@ -30,6 +30,7 @@ func TestParseInput(t *testing.T) {
{"_No response_", true, "", ""},
{"None", true, "", ""},
{"hello", true, "hello", ""},
+ {"Testing formatting and link stripping", true, "Testing formatting and link stripping", ""},
}
runValidationTests(t, testCases, ParseInput, "ParseInput")
}
@@ -39,7 +40,6 @@ func TestParsePlainString(t *testing.T) {
{"", true, "", ""},
{"Hello world", true, "Hello world", ""},
{"π howdy", false, "π howdy", "cannot contain emoji characters"},
- {"Testing formatting and link stripping", true, "Testing formatting and link stripping", ""},
}
runValidationTests(t, testCases, ParsePlainString, "ParsePlainString")
}