-
Notifications
You must be signed in to change notification settings - Fork 5
refactor: use coder/slog + minor go style changes #107
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
base: main
Are you sure you want to change the base?
Changes from all commits
2c20ae5
b1d22f2
6b4093c
097b8a2
ed629c1
85743cd
6e8fc77
4fc0a54
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 |
---|---|---|
@@ -1,9 +1,9 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"log" | ||
"net/url" | ||
"os" | ||
"path" | ||
|
@@ -35,7 +35,7 @@ type contributorProfileReadme struct { | |
|
||
func validateContributorDisplayName(displayName string) error { | ||
if displayName == "" { | ||
return fmt.Errorf("missing display_name") | ||
return errors.New("missing display_name") | ||
} | ||
|
||
return nil | ||
|
@@ -53,17 +53,16 @@ func validateContributorLinkedinURL(linkedinURL *string) error { | |
return nil | ||
} | ||
|
||
// validateContributorSupportEmail does best effort validation of a contributors email address. We can't 100% validate | ||
// that this is correct without actually sending an email, especially because some contributors are individual developers | ||
// and we don't want to do that on every single run of the CI pipeline. The best we can do is verify the general structure. | ||
func validateContributorSupportEmail(email *string) []error { | ||
if email == nil { | ||
return nil | ||
} | ||
|
||
errs := []error{} | ||
|
||
// Can't 100% validate that this is correct without actually sending | ||
// an email, and especially with some contributors being individual | ||
// developers, we don't want to do that on every single run of the CI | ||
// pipeline. Best we can do is verify the general structure | ||
username, server, ok := strings.Cut(*email, "@") | ||
if !ok { | ||
errs = append(errs, fmt.Errorf("email address %q is missing @ symbol", *email)) | ||
|
@@ -113,21 +112,18 @@ func validateContributorStatus(status string) error { | |
return nil | ||
} | ||
|
||
// Can't validate the image actually leads to a valid resource in a pure | ||
// function, but can at least catch obvious problems | ||
// Can't validate the image actually leads to a valid resource in a pure function, but can at least catch obvious problems. | ||
func validateContributorAvatarURL(avatarURL *string) []error { | ||
if avatarURL == nil { | ||
return nil | ||
} | ||
|
||
errs := []error{} | ||
if *avatarURL == "" { | ||
errs = append(errs, errors.New("avatar URL must be omitted or non-empty string")) | ||
return errs | ||
return []error{errors.New("avatar URL must be omitted or non-empty string")} | ||
} | ||
|
||
// Have to use .Parse instead of .ParseRequestURI because this is the | ||
// one field that's allowed to be a relative URL | ||
errs := []error{} | ||
// Have to use .Parse instead of .ParseRequestURI because this is the one field that's allowed to be a relative URL. | ||
if _, err := url.Parse(*avatarURL); err != nil { | ||
errs = append(errs, fmt.Errorf("URL %q is not a valid relative or absolute URL", *avatarURL)) | ||
} | ||
|
@@ -220,8 +216,7 @@ func parseContributorFiles(readmeEntries []readme) (map[string]contributorProfil | |
|
||
yamlValidationErrors := []error{} | ||
for _, p := range profilesByNamespace { | ||
errors := validateContributorReadme(p) | ||
if len(errors) > 0 { | ||
if errors := validateContributorReadme(p); len(errors) > 0 { | ||
yamlValidationErrors = append(yamlValidationErrors, errors...) | ||
continue | ||
} | ||
|
@@ -245,11 +240,12 @@ func aggregateContributorReadmeFiles() ([]readme, error) { | |
allReadmeFiles := []readme{} | ||
errs := []error{} | ||
for _, e := range dirEntries { | ||
dirPath := path.Join(rootRegistryPath, e.Name()) | ||
if !e.IsDir() { | ||
continue | ||
} | ||
|
||
dirPath := path.Join(rootRegistryPath, e.Name()) | ||
cstyan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
readmePath := path.Join(dirPath, "README.md") | ||
rmBytes, err := os.ReadFile(readmePath) | ||
if err != nil { | ||
|
@@ -273,20 +269,17 @@ func aggregateContributorReadmeFiles() ([]readme, error) { | |
} | ||
|
||
func validateContributorRelativeUrls(contributors map[string]contributorProfileReadme) error { | ||
// This function only validates relative avatar URLs for now, but it can be | ||
// beefed up to validate more in the future | ||
// This function only validates relative avatar URLs for now, but it can be beefed up to validate more in the future. | ||
errs := []error{} | ||
|
||
for _, con := range contributors { | ||
// If the avatar URL is missing, we'll just assume that the Registry | ||
// site build step will take care of filling in the data properly | ||
// If the avatar URL is missing, we'll just assume that the Registry site build step will take care of filling | ||
// in the data properly. | ||
if con.frontmatter.AvatarURL == nil { | ||
continue | ||
} | ||
|
||
isRelativeURL := strings.HasPrefix(*con.frontmatter.AvatarURL, ".") || | ||
strings.HasPrefix(*con.frontmatter.AvatarURL, "/") | ||
if !isRelativeURL { | ||
if !strings.HasPrefix(*con.frontmatter.AvatarURL, ".") || !strings.HasPrefix(*con.frontmatter.AvatarURL, "/") { | ||
continue | ||
} | ||
|
||
|
@@ -297,8 +290,7 @@ func validateContributorRelativeUrls(contributors map[string]contributorProfileR | |
|
||
absolutePath := strings.TrimSuffix(con.filePath, "README.md") + | ||
*con.frontmatter.AvatarURL | ||
_, err := os.ReadFile(absolutePath) | ||
if err != nil { | ||
if _, err := os.ReadFile(absolutePath); err != nil { | ||
errs = append(errs, fmt.Errorf("%q: relative avatar path %q does not point to image in file system", con.filePath, *con.frontmatter.AvatarURL)) | ||
} | ||
} | ||
|
@@ -318,19 +310,18 @@ func validateAllContributorFiles() error { | |
return err | ||
} | ||
|
||
log.Printf("Processing %d README files\n", len(allReadmeFiles)) | ||
logger.Info(context.Background(), "Processing README files", "num_files", len(allReadmeFiles)) | ||
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. I'm still new to structured logging. Is there any special behavior/benefit you get if you use the same key multiple times? I guess I'm just wondering how much of a concern it is to make sure you're using the same keys each time you describe the same "resource", particularly for a function call that takes a variadic slice of empty interfaces (so basically zero type-safety) 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. It's not the end of the world if you don't use the same key, but it does make searching for logs in some kind of log aggregation system much easier. For example, a system I used to work on referred to the same internal Again this is likely less important in the case of the registry but still a good practice. |
||
contributors, err := parseContributorFiles(allReadmeFiles) | ||
if err != nil { | ||
return err | ||
} | ||
log.Printf("Processed %d README files as valid contributor profiles", len(contributors)) | ||
logger.Info(context.Background(), "Processed README files as valid contributor profiles", "num_contributors", len(contributors)) | ||
|
||
err = validateContributorRelativeUrls(contributors) | ||
if err != nil { | ||
if err = validateContributorRelativeUrls(contributors); err != nil { | ||
return err | ||
} | ||
log.Println("All relative URLs for READMEs are valid") | ||
logger.Info(context.Background(), "All relative URLs for READMEs are valid") | ||
|
||
log.Printf("Processed all READMEs in the %q directory\n", rootRegistryPath) | ||
logger.Info(context.Background(), "Processed all READMEs in directory", "dir", rootRegistryPath) | ||
return nil | ||
} |
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'm not sure I understand the point of this change, since
nextLine
isn't ever used outside the loop. I'm not a fan of scope pollution, and try to keep scoping as aggressively small as possible, even in the same functionrange
loops. Does the below example have the same problems as the old approach, where we're declaring new block-scoped variables on the stack once per iteration?Is there an optimization that
range
loops have that doesn't exist with other loops?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.
Yeah this is just an optimization to reduce memory allocations. Very minor in this case since I doubt this loop has a lot of iterations, but without this a new string for
nextLine
is allocated for each iteration of the loop.The Go compiler already does an optimization itself for
for thing := range anotherThing
to do the same optimization, assigning to the same var for each iteration rather than allocating a new one every time.