-
-
Notifications
You must be signed in to change notification settings - Fork 0
Add SEO generation for About, Projects, and Resume pages #117
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
Add SEO generation for About, Projects, and Resume pages #117
Conversation
|
Caution Review failedThe pull request is closed. Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a generic fetch helper and new Client getters (social, recommendations, experience, education); extends Generator to orchestrate About/Projects/Resume/Posts pages with per-page build helpers; implements rendering for posts and new sections; updates fixtures, defaults, manifest, portal utilities, and tests. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant CLI as CLI (caller)
participant Gen as Generator
participant Client as SEO Client
participant Sections as Renderer
participant Export as Exporter
CLI->>Gen: Generate()
note right of Gen: Orchestrates multiple page builds
rect rgb(236,245,255)
Gen->>Gen: GenerateAbout()
Gen->>Client: GetProfile(), GetSocial(), GetRecommendations()
Client-->>Gen: Profile, Social, Recs
Gen->>Sections: Render About (profile, social, recs)
Sections-->>Gen: HTML body
Gen->>Export: Export(about.seo.html)
Export-->>Gen: OK
end
rect rgb(240,255,240)
Gen->>Gen: GenerateProjects()
Gen->>Client: GetProjects()
Client-->>Gen: Projects
Gen->>Sections: Render Projects
Sections-->>Gen: HTML body
Gen->>Export: Export(projects.seo.html)
Export-->>Gen: OK
end
rect rgb(255,248,236)
Gen->>Gen: GenerateResume()
Gen->>Client: GetExperience(), GetEducation(), GetRecommendations()
Client-->>Gen: Exp, Edu, Recs
Gen->>Sections: Render Resume
Sections-->>Gen: HTML body
Gen->>Export: Export(resume.seo.html)
Export-->>Gen: OK
end
rect rgb(245,245,255)
Gen->>Gen: GeneratePosts()
Gen->>Client: GetPosts()
Client-->>Gen: Posts
loop per post
Gen->>Gen: BuildForPost(post)
Gen->>Sections: Render Post
Sections-->>Gen: HTML body
Gen->>Export: Export(posts/<slug>.seo.html)
Export-->>Gen: OK
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @gocanto, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the application's SEO capabilities by integrating more content types into the SEO generation process. It introduces the ability to create specific SEO-optimized pages for 'About', 'Projects', and 'Resume' sections, ensuring that rich, structured data from social links, recommendations, and professional history is properly exposed to search engines. This change aims to improve the overall discoverability and ranking of these key web pages. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
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.
Code Review
This pull request extends the SEO generation to cover the About, Projects, and Resume pages. The changes are well-structured, introducing new client methods, section renderers, and generator functions, along with corresponding tests. My feedback focuses on improving maintainability by reducing code duplication and adhering to idiomatic Go practices. I've identified several areas where helper functions could be used to create more concise and DRY code.
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.
Actionable comments posted: 1
🧹 Nitpick comments (6)
metal/cli/seo/client_test.go (1)
97-131: Subtest structure would improve readability and isolation.Consider using t.Run for each payload (social, recommendations, experience, education) so failures don't mask subsequent checks and output is scoped.
metal/cli/seo/generator_test.go (1)
109-182: Solid end-to-end assertions for newly generated pages.As a follow-up, consider asserting page-specific <title> and canonical link tags to exercise titleFor/canonicalFor and Build validation more directly.
metal/router/fixture.go (1)
42-44: Avoid mutating the receiver when resolving fixtures.resolveFor assigns clone := f (pointer copy), then mutates fields, which mutates the original Fixture. This can cause subtle bugs if the same Fixture is reused. Copy the struct value instead.
Outside the changed lines, update resolveFor as:
func (f *Fixture) resolveFor(slug string) *Fixture { clone := *f // copy by value, not by pointer clone.fullPath = clone.getFileFor(slug) clone.file = slug return &clone }Also applies to: 66-68, 74-76, 82-84
metal/cli/seo/sections.go (1)
3-4: Minor HTML semantics and micro-optimizations.
- Consider removing the surrounding
around
blocks;
should not be nested in
. Repeat across sections for consistency.
- allowLineBreaks creates a new Replacer on each call; a package-level var would avoid allocations. Example:
var brReplacer = strings.NewReplacer("<br/>", "
", "<br />", "
", "<br>", "
")
and return brReplacer.Replace(text).Also applies to: 143-188, 190-240, 242-286, 305-314
metal/cli/seo/client.go (1)
67-121: Client extensions follow existing pattern cleanly.Consistent error wrapping and fetch usage. If duplication grows, consider a small generic helper to DRY the fetch+wrap pattern.
metal/cli/seo/generator.go (1)
362-374: Normalize path input in canonicalFor for extra safety.Guard against paths lacking a leading slash to avoid accidental concatenation issues if constants change.
Apply this diff:
func (g *Generator) canonicalFor(path string) string { base := strings.TrimSuffix(g.Page.SiteURL, "/") if path == "" || path == "/" { return base } + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + if strings.HasSuffix(base, path) { return base } return base + path }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
metal/cli/seo/client.go(1 hunks)metal/cli/seo/client_test.go(1 hunks)metal/cli/seo/generator.go(7 hunks)metal/cli/seo/generator_test.go(3 hunks)metal/cli/seo/sections.go(3 hunks)metal/cli/seo/sections_test.go(2 hunks)metal/router/fixture.go(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
metal/cli/seo/sections_test.go (4)
handler/payload/social.go (2)
SocialResponse(3-6)SocialData(8-14)handler/payload/recommendations.go (3)
RecommendationsResponse(3-6)RecommendationsData(8-15)RecommendationsPersonData(17-22)handler/payload/experience.go (2)
ExperienceResponse(3-6)ExperienceData(8-20)handler/payload/education.go (2)
EducationResponse(3-6)EducationData(8-17)
metal/cli/seo/sections.go (4)
handler/payload/social.go (1)
SocialResponse(3-6)handler/payload/recommendations.go (1)
RecommendationsResponse(3-6)handler/payload/experience.go (1)
ExperienceResponse(3-6)handler/payload/education.go (1)
EducationResponse(3-6)
metal/cli/seo/client.go (10)
handler/payload/social.go (1)
SocialResponse(3-6)metal/router/static.go (1)
StaticRouteResource(10-12)handler/social.go (1)
MakeSocialHandler(16-20)metal/router/fixture.go (1)
Fixture(15-20)handler/payload/recommendations.go (1)
RecommendationsResponse(3-6)handler/recommendations.go (1)
MakeRecommendationsHandler(16-20)handler/payload/experience.go (1)
ExperienceResponse(3-6)handler/experience.go (1)
MakeExperienceHandler(16-20)handler/payload/education.go (1)
EducationResponse(3-6)handler/education.go (1)
MakeEducationHandler(16-20)
metal/cli/seo/generator.go (9)
handler/payload/profile.go (1)
ProfileResponse(3-6)handler/payload/social.go (1)
SocialResponse(3-6)handler/payload/recommendations.go (1)
RecommendationsResponse(3-6)metal/cli/seo/client.go (1)
Client(13-16)metal/cli/seo/sections.go (1)
NewSections(13-15)metal/cli/seo/defaults.go (8)
WebAboutName(16-16)WebAboutUrl(17-17)WebProjectsName(22-22)WebProjectsUrl(23-23)WebResumeName(19-19)WebResumeUrl(20-20)WebHomeName(14-14)WebHomeUrl(13-13)handler/payload/experience.go (1)
ExperienceResponse(3-6)handler/payload/education.go (1)
EducationResponse(3-6)metal/cli/seo/data.go (2)
TemplateData(20-38)Page(5-18)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: test (1.25.1)
- GitHub Check: test (1.25.1)
🔇 Additional comments (2)
metal/cli/seo/sections_test.go (1)
33-41: Good coverage of escaping and allowed tags across new sections.The new fixtures and assertions validate both escaping and the deliberate allowance of
in recommendations. Aggregation check for headings is consistent with the new renderers.Also applies to: 42-53, 54-67, 69-78, 107-111, 112-116, 117-121, 122-126, 133-136
metal/cli/seo/generator.go (1)
85-96: New page generation flow looks correct and cohesive.Good separation per page and reuse of buildForPage/canonicalFor/titleFor. Error messages are contextualized per page.
Also applies to: 143-182, 184-206, 207-246, 279-341
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.
Actionable comments posted: 3
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
metal/cli/seo/client.go(1 hunks)metal/cli/seo/defaults.go(1 hunks)metal/cli/seo/generator.go(10 hunks)metal/cli/seo/generator_test.go(4 hunks)metal/cli/seo/manifest.go(1 hunks)metal/cli/seo/sections.go(6 hunks)metal/cli/seo/sections_test.go(3 hunks)metal/cli/seo/testhelpers_test.go(4 hunks)pkg/portal/support.go(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- metal/cli/seo/sections_test.go
🧰 Additional context used
🧬 Code graph analysis (6)
metal/cli/seo/manifest.go (1)
metal/cli/seo/defaults.go (2)
WebPostsUrl(20-20)WebPostsName(19-19)
metal/cli/seo/generator.go (5)
metal/cli/seo/defaults.go (11)
WebHomeName(14-14)WebHomeUrl(13-13)WebAboutName(16-16)WebAboutUrl(17-17)WebProjectsName(25-25)WebProjectsUrl(26-26)WebResumeName(22-22)WebResumeUrl(23-23)Description(35-35)AboutPhotoUrl(9-9)WebPostsUrl(20-20)pkg/cli/message.go (4)
Successln(17-19)Error(5-7)Grayln(57-59)Cyanln(49-51)handler/payload/posts.go (2)
GetPostsResponse(54-79)PostResponse(21-36)metal/cli/seo/data.go (2)
Page(5-18)TemplateData(20-38)metal/cli/seo/manifest.go (2)
Manifest(10-24)NewManifest(41-99)
metal/cli/seo/sections.go (6)
pkg/portal/support.go (3)
SanitizeURL(39-49)FilterNonEmpty(27-37)AllowLineBreaks(17-25)handler/payload/posts.go (1)
PostResponse(21-36)handler/payload/social.go (1)
SocialResponse(3-6)handler/payload/recommendations.go (1)
RecommendationsResponse(3-6)handler/payload/experience.go (1)
ExperienceResponse(3-6)handler/payload/education.go (1)
EducationResponse(3-6)
metal/cli/seo/testhelpers_test.go (6)
database/connection.go (1)
Connection(12-17)database/model.go (3)
Category(106-118)Tag(127-139)User(57-81)database/repository/posts.go (1)
Posts(13-17)database/repository/categories.go (1)
Categories(13-15)database/repository/tags.go (1)
Tags(13-15)database/attrs.go (3)
PostsAttrs(62-72)CategoriesAttrs(19-24)TagAttrs(26-30)
metal/cli/seo/generator_test.go (2)
metal/cli/seo/defaults.go (2)
WebHomeName(14-14)WebHomeUrl(13-13)database/model.go (5)
User(57-81)Category(106-118)PostCategory(120-125)Tag(127-139)PostTag(141-146)
metal/cli/seo/client.go (8)
metal/router/static.go (1)
StaticRouteResource(10-12)handler/talks.go (1)
MakeTalksHandler(16-20)handler/profile.go (1)
MakeProfileHandler(16-20)handler/projects.go (1)
MakeProjectsHandler(16-20)handler/social.go (1)
MakeSocialHandler(16-20)handler/recommendations.go (1)
MakeRecommendationsHandler(16-20)handler/experience.go (1)
MakeExperienceHandler(16-20)handler/education.go (1)
MakeEducationHandler(16-20)
🪛 GitHub Actions: Tests
metal/cli/seo/generator_test.go
[error] 201-201: TestGeneratorGenerateAllPages failed: expected escaped post title in seo output. The test expected a specific HTML-escaped title string but it was not matched.
🔇 Additional comments (11)
metal/cli/seo/testhelpers_test.go (4)
126-140: LGTM!The updated signature returning
database.Categoryimproves usability by allowing callers to access the created entity directly.
142-156: LGTM!The function follows the established pattern for seed helpers and correctly creates and returns a tag entity.
158-190: LGTM!The helper correctly constructs a test user with appropriate defaults. The display name logic gracefully handles empty name components.
192-227: LGTM!The helper correctly uses the repository pattern to create a post with proper associations. All required fields are populated appropriately for testing.
metal/cli/seo/defaults.go (1)
19-20: LGTM!The new Posts page constants follow the established naming pattern and are appropriately positioned with other web page definitions.
metal/cli/seo/manifest.go (1)
77-82: LGTM!The new Posts shortcut is correctly structured and positioned consistently with the other manifest shortcuts.
pkg/portal/support.go (2)
27-37: LGTM!The function correctly filters and trims non-empty values from the input slice.
17-25: No action needed: inputs to AllowLineBreaks are always pre-escaped.Every call site (
excerpt,item.Text,item.Description, and paragraph content) appliestemplate.HTMLEscapeString(and only then replaces newline markers) before passing toAllowLineBreaks, ensuring no unescaped HTML can be injected.metal/cli/seo/client.go (3)
25-33: Generic helper successfully addresses code duplication.The extracted
get[T]function effectively eliminates the boilerplate that was previously duplicated across multiple methods, directly addressing the earlier review feedback.
35-51: LGTM!The refactoring successfully simplifies these methods while maintaining identical behavior. The code is now more maintainable and consistent.
53-75: LGTM!The new getter methods follow the established pattern and correctly utilize the generic helper, maintaining consistency across the client interface.
Summary
Testing
https://chatgpt.com/codex/tasks/task_e_68d654e275688333b138e642b49386ac
Summary by CodeRabbit
New Features
Improvements