Skip to content

Commit

Permalink
feat: first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
huantt committed Sep 13, 2023
0 parents commit aac92c9
Show file tree
Hide file tree
Showing 28 changed files with 1,413 additions and 0 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/run.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: "Cronjob"
on:
schedule:
- cron: '15 */6 * * *'
release:
types: [published]

jobs:
update-weather:
permissions: write-all
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Update articles
uses: huantt/[email protected]
with:
template-file: 'README.md.template'
out-file: 'README.md'
- name: Commit
run: |
git config user.name github-actions
git config user.email [email protected]
git add .
git commit -m "update"
git push origin main
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea/
.test/
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM golang:1.21-bullseye as builder

ENV CGO_ENABLED=1
ENV GOOS=linux
ENV GOARCH=amd64
ENV GO111MODULE=on
WORKDIR /app
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN go build -o app

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y tzdata ca-certificates
RUN mkdir /app
WORKDIR /app
COPY --from=builder /app/app .
RUN ln -s /app/app /bin/articles-updater
ENTRYPOINT ["articles-updater", "update-articles"]
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
## About
Collect your latest articles from sources such as [dev.to](https://dev.to), and then update the `README.md`.

## Use GitHub Action to update your README

**Step 1:** In your repository, create a file named `README.md.template`.

**Step 2:** Write anything you want within the `README.md.template` file.

**Step 3:** Embed one of the following entities within your `README.md.template`:

- **Article listing:**
```shell
{{ template "article-list" .Articles }}
```

If you are familiar with Go templates, you have access to the `root` variable, which includes the following fields:

- `Articles`: An array of Article. You can view the Article struct definition in [model/article.go](model/article.go).
- `Time`: Updated Time

**Step 4**: Register Github Action
- Create a file `.github/workflows/update-articles.yml` in your repository.
```yml
name: "Cronjob"
on:
schedule:
- cron: '15 0 * * *'

jobs:
update-articles:
permissions: write-all
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Generate README
uses: huantt/[email protected]
with:
username: YOUR_USERNAME_ON_DEV_TO
template-file: 'README.md.template'
out-file: 'README.md'
limit: 5
- name: Commit
run: |
git config user.name github-actions
git config user.email [email protected]
git add .
git commit -m "update articles"
git push origin main
```
**Step 5**: Commit your change, then Github actions will run as your specified cron to update Articles into your README.md file
## Below is my recent articles Jack collected from dev.to
- [Creating Dynamic README.md File](https://dev.to/jacktt/creating-dynamic-readmemd-file-388o) - 09/09/2023
- [Search Goole Like a Pro [Cheat sheet]](https://dev.to/jacktt/search-goole-like-a-pro-cheat-sheet-555g) - 30/08/2023
- [Advanced Go Build Techniques](https://dev.to/jacktt/go-build-in-advance-4o8n) - 30/08/2023
- [Load Private Module in Golang Project](https://dev.to/jacktt/load-private-module-in-golang-project-122l) - 12/08/2023
- [Speed up your query in Postgres](https://dev.to/jacktt/speed-up-your-query-in-postgres-48e3) - 23/06/2023
*Updated at: 2023-09-13T19:51:42+07:00*
58 changes: 58 additions & 0 deletions README.md.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
## About
Collect your latest articles from sources such as [dev.to](https://dev.to), and then update the `README.md`.

## Use GitHub Action to update your README

**Step 1:** In your repository, create a file named `README.md.template`.

**Step 2:** Write anything you want within the `README.md.template` file.

**Step 3:** Embed one of the following entities within your `README.md.template`:

- **Article listing:**
```shell
{{`{{`}} template "article-list" .Articles {{`}}`}}
```

If you are familiar with Go templates, you have access to the `root` variable, which includes the following fields:

- `Articles`: An array of Article. You can view the Article struct definition in [model/article.go](model/article.go).
- `Time`: Updated Time

**Step 4**: Register Github Action
- Create a file `.github/workflows/update-articles.yml` in your repository.
```yml
name: "Cronjob"
on:
schedule:
- cron: '15 0 * * *'

jobs:
update-articles:
permissions: write-all
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Generate README
uses: huantt/[email protected]
with:
username: YOUR_USERNAME_ON_DEV_TO
template-file: 'README.md.template'
out-file: 'README.md'
limit: 5
- name: Commit
run: |
git config user.name github-actions
git config user.email [email protected]
git add .
git commit -m "update articles"
git push origin main
```

**Step 5**: Commit your change, then Github actions will run as your specified cron to update Articles into your README.md file

## Below is my recent articles {{ .Author }} collected from dev.to

{{ template "article-list" .Articles }}

*Updated at: {{ formatTime .Time }}*
24 changes: 24 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: 'Article updater'
description: 'Collect articles then lists to README.md'
inputs:
username:
description: 'Username'
required: true
template-file:
description: 'Template file path'
required: true
out-file:
description: 'Output file path'
required: true
limit:
description: 'Limit number of articles'
required: false
default: '5'
runs:
using: 'docker'
image: 'Dockerfile'
args:
- --limit=${{ inputs.limit }}
- --username=${{ inputs.username }}
- --template-file=${{ inputs.template-file }}
- --out-file=${{ inputs.out-file }}
54 changes: 54 additions & 0 deletions cmd/weather.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package cmd

import (
"context"
"github.com/huantt/article-listing/handler/collector"
"github.com/huantt/article-listing/impl/article_service/forem"
foremsrv "github.com/huantt/article-listing/pkg/forem"
"github.com/spf13/cobra"
"log/slog"
"os"
)

func UpdateWeather(use string) *cobra.Command {
var templateFilePath string
var outputFilePath string
var username string
var limit int

command := &cobra.Command{
Use: use,
Run: func(cmd *cobra.Command, args []string) {
devToService := forem.NewService(foremsrv.NewService(foremsrv.DevToEndpoint))
handler := collector.NewHandler(devToService)
err := handler.Collect(context.Background(), username, limit, templateFilePath, outputFilePath)
if err != nil {
slog.Error(err.Error())
os.Exit(1)
}
slog.Info("Updated!")
},
}

command.Flags().StringVarP(&templateFilePath, "template-file", "f", "", "Readme template file path")
command.Flags().StringVarP(&outputFilePath, "out-file", "o", "", "Output file path")
command.Flags().StringVarP(&username, "username", "u", "", "Username")
command.Flags().IntVar(&limit, "limit", 5, "Limit number of articles")
err := command.MarkFlagRequired("username")
if err != nil {
slog.Error(err.Error())
os.Exit(1)
}
err = command.MarkFlagRequired("template-file")
if err != nil {
slog.Error(err.Error())
os.Exit(1)
}
err = command.MarkFlagRequired("out-file")
if err != nil {
slog.Error(err.Error())
os.Exit(1)
}

return command
}
3 changes: 3 additions & 0 deletions data/template.md.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Top articles

{{ template "article-list" $.Articles }}
16 changes: 16 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module github.com/huantt/article-listing

go 1.21

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-resty/resty/v2 v2.7.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/cobra v1.7.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
golang.org/x/net v0.0.0-20211029224645-99673261e6eb // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
34 changes: 34 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb h1:pirldcYWx7rx7kE5r+9WsOXPXK0+WH5+uZ7uPmJ44uM=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
76 changes: 76 additions & 0 deletions handler/collector/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package collector

import (
"bytes"
"context"
"errors"
"fmt"
"github.com/huantt/article-listing/model"
"html/template"
"log/slog"
"os"
"time"
)

type Handler struct {
articleService ArticleService
}

func NewHandler(articleService ArticleService) *Handler {
return &Handler{articleService}
}

func (h *Handler) Collect(ctx context.Context, username string, limit int, templateFilePath, outputFilePath string) error {
articles, err := h.articleService.GetArticles(ctx, username, 1, limit)
if err != nil {
return err
}
slog.Info(fmt.Sprintf("Got %d article from %s", len(articles), username))

templateStr, err := os.ReadFile(templateFilePath)
if err != nil {
return err
}
output, err := generateOutput(articles, string(templateStr), templates...)
if err != nil {
return err
}
return os.WriteFile(outputFilePath, []byte(*output), 0644)
}

func generateOutput(articles []model.Article, readmeTemplate string, templates ...string) (*string, error) {
if len(articles) == 0 {
return nil, errors.New("articles must be not empty")
}
tmpl, err := template.
New("article").
Funcs(template.FuncMap{
"formatDate": formatDate,
"formatHour": formatHour,
"formatTime": formatTime,
"truncateByWords": truncateByWords,
}).
Parse(readmeTemplate)
if err != nil {
return nil, err
}

for _, t := range templates {
tmpl, err = tmpl.Parse(t)
if err != nil {
return nil, err
}
}

var result bytes.Buffer
err = tmpl.ExecuteTemplate(&result, "article", map[string]any{
"Articles": articles,
"Author": articles[0].Author,
"Time": time.Now(),
})
if err != nil {
return nil, err
}
stringResult := result.String()
return &stringResult, nil
}
Loading

0 comments on commit aac92c9

Please sign in to comment.