-
Notifications
You must be signed in to change notification settings - Fork 790
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add application parsing and validation, test issues
- Loading branch information
1 parent
4b37c28
commit e2a4404
Showing
11 changed files
with
702 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"log" | ||
"strings" | ||
"time" | ||
|
||
"github.com/google/go-github/v60/github" | ||
) | ||
|
||
type Project struct { | ||
Name string `json:"name"` | ||
Description string `json:"description"` | ||
Contributors int `json:"contributors"` | ||
HomeUrl string `json:"home_url"` | ||
RepoUrl string `json:"repo_url,omitempty"` | ||
LicenseType string `json:"license_type,omitempty"` | ||
LicenseUrl string `json:"license_url,omitempty"` | ||
IsEvent bool `json:"is_event"` | ||
IsTeam bool `json:"is_team"` | ||
} | ||
|
||
type Applicant struct { | ||
Name string `json:"name"` | ||
Email string `json:"email"` | ||
Role string `json:"role"` | ||
Id int64 `json:"id"` | ||
} | ||
|
||
type Application struct { | ||
validator Validator `json:"-"` | ||
sections map[string]string `json:"-"` | ||
Problems []error `json:"-"` | ||
|
||
Account string `json:"account"` | ||
Project Project `json:"project"` | ||
Applicant Applicant `json:"applicant"` | ||
CanContact bool `json:"can_contact"` | ||
ApproverId int `json:"approver_id,omitempty"` | ||
IssueNumber int `json:"issue_number"` | ||
CreatedAt time.Time `json:"created_at"` | ||
} | ||
|
||
func (a *Application) Parse(issue github.Issue) { | ||
a.validator = Validator{} | ||
|
||
if strings.Contains(*issue.Title, "[project name]") { | ||
a.validator.AddError("Application title", *issue.Title, "is missing project name") | ||
} | ||
|
||
a.sections = a.extractSections(*issue.Body) | ||
|
||
if isTestingIssue() { | ||
data, err := json.MarshalIndent(a.sections, "", "\t") | ||
if err != nil { | ||
log.Fatalf("Could not marshal Sections input data: %s", err.Error()) | ||
} | ||
|
||
debugMessage("Parsed input data:", string(data)) | ||
} | ||
|
||
a.CreatedAt = issue.CreatedAt.Time | ||
a.IssueNumber = *issue.Number | ||
a.Account = a.stringSection("Account URL", IsPresent, ParseAccountUrl) | ||
a.boolSection("Non-commercial confirmation", IsPresent, ParseCheckbox, IsChecked) | ||
|
||
a.Project.IsTeam = a.boolSection("Team application", ParseCheckbox) | ||
a.Project.IsEvent = a.boolSection("Event application", ParseCheckbox) | ||
|
||
isProject := !a.Project.IsTeam && !a.Project.IsEvent | ||
|
||
a.Project.Name = a.stringSection("Project name", IsPresent, IsRegularString) | ||
a.Project.Description = a.stringSection("Short description", IsPresent, IsRegularString) | ||
a.Project.Contributors = a.intSection("Number of team members/core contributors", IsPresent, IsRegularString) | ||
a.Project.HomeUrl = a.stringSection("Homepage URL", IsPresent, IsUrl) | ||
a.Project.RepoUrl = a.stringSection("Repository URL", IsUrl) | ||
a.Project.LicenseType = a.stringSection("License type", When(isProject, IsPresent), IsRegularString) | ||
a.Project.LicenseUrl = a.stringSection("License URL", When(isProject, IsPresent), IsUrl) | ||
a.boolSection("Age confirmation", When(isProject, IsPresent), ParseCheckbox, When(isProject, IsChecked)) | ||
|
||
a.Applicant.Name = a.stringSection("Name", IsPresent, IsRegularString) | ||
a.Applicant.Email = a.stringSection("Email", IsPresent, IsEmail) | ||
a.Applicant.Role = a.stringSection("Project role", IsPresent, IsProjectRole) | ||
a.Applicant.Id = *issue.User.ID | ||
|
||
a.stringSection("Profile or website", IsUrl) | ||
a.stringSection("Additional comments") | ||
|
||
a.CanContact = a.boolSection("Can we contact you?", ParseCheckbox) | ||
|
||
if isTestingIssue() { | ||
debugMessage("Application data:", a.GetData()) | ||
} | ||
|
||
for _, err := range a.validator.Errors { | ||
a.Problems = append(a.Problems, fmt.Errorf(err.Error())) | ||
} | ||
} | ||
|
||
func (a *Application) IsValid() bool { | ||
return len(a.Problems) == 0 | ||
} | ||
|
||
func (a *Application) GetData() string { | ||
data, err := json.MarshalIndent(a, "", "\t") | ||
if err != nil { | ||
log.Fatalf("Could not marshal Application data: %s", err.Error()) | ||
} | ||
|
||
return string(data) | ||
} | ||
|
||
func (a *Application) extractSections(body string) map[string]string { | ||
sections := make(map[string]string) | ||
|
||
lines := strings.Split(body, "\n") | ||
var currentHeader string | ||
contentBuilder := strings.Builder{} | ||
|
||
for _, line := range lines { | ||
trimmedLine := strings.TrimSpace(line) | ||
if strings.HasPrefix(trimmedLine, "### ") { | ||
if currentHeader != "" { | ||
sections[currentHeader] = strings.TrimSpace(contentBuilder.String()) | ||
contentBuilder.Reset() | ||
} | ||
currentHeader = strings.TrimSpace(trimmedLine[4:]) | ||
} else if currentHeader != "" { | ||
contentBuilder.WriteString(line + "\n") | ||
} | ||
} | ||
|
||
if currentHeader != "" { | ||
sections[currentHeader] = strings.TrimSpace(contentBuilder.String()) | ||
} | ||
|
||
return sections | ||
} | ||
|
||
func (a *Application) stringSection(sectionName string, callbacks ...ValidatorCallback) string { | ||
value, exists := a.sections[sectionName] | ||
|
||
if !exists { | ||
a.validator.AddError(sectionName, value, "was not completed for application") | ||
return value | ||
} | ||
|
||
// everything gets passed through ParseInput first | ||
callbacks = append([]ValidatorCallback{ParseInput}, callbacks...) | ||
|
||
for _, callback := range callbacks { | ||
pass, newValue, message := callback(value) | ||
value = newValue | ||
|
||
if !pass { | ||
a.validator.AddError(sectionName, value, message) | ||
break | ||
} | ||
} | ||
|
||
return value | ||
} | ||
|
||
func (a *Application) intSection(sectionName string, callbacks ...ValidatorCallback) int { | ||
value := a.stringSection(sectionName, callbacks...) | ||
|
||
// don't bother proceeding if there's already an error parsing the string | ||
if a.validator.HasError(sectionName) { | ||
return 0 | ||
} | ||
|
||
pass, number, message := ParseNumber(value) | ||
if !pass { | ||
a.validator.AddError(sectionName, fmt.Sprintf("%d", number), message) | ||
return 0 | ||
} | ||
|
||
return number | ||
} | ||
|
||
func (a *Application) boolSection(sectionName string, callbacks ...ValidatorCallback) bool { | ||
value := a.stringSection(sectionName, callbacks...) | ||
|
||
// don't bother proceeding if there's already an error parsing the string | ||
if a.validator.HasError(sectionName) { | ||
return false | ||
} | ||
|
||
pass, boolean, message := ParseBool(value) | ||
if !pass { | ||
a.validator.AddError(sectionName, fmt.Sprintf("%t", boolean), message) | ||
return false | ||
} | ||
|
||
return boolean | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
{ | ||
"id": 1801650328, | ||
"number": 6, | ||
"state": "open", | ||
"locked": false, | ||
"title": "Application for [project name]", | ||
"body": "### Account URL\n\nfoo\n\n### Non-commercial confirmation\n\n- [ ] 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\n[TestDB](https://testdb.com) is a free and open source, community-based forum software project.\n\n### Number of team members/core contributors\n\nfoo\n\n### Homepage URL\n\n@wendyappleed\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\[email protected]\n\n### Project role\n\nLead Dev\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" | ||
}, | ||
"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" | ||
} |
Oops, something went wrong.