Skip to content

Commit 2372cf8

Browse files
authored
master << develop (#25)
2 parents 9c557e3 + 2abc193 commit 2372cf8

File tree

14 files changed

+1008
-43
lines changed

14 files changed

+1008
-43
lines changed

Dockerfile

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
1-
FROM golang:1.22
1+
# Build stage
2+
FROM golang:1.24 AS builder
23

3-
ENV GITHUB_TOKEN=${GITHUB_TOKEN}
4+
WORKDIR /build
5+
COPY go.mod go.sum ./
6+
RUN go mod download
47

5-
COPY . /home/src
6-
WORKDIR /home/src
7-
RUN go build -o /bin/cmd ./cmd
8+
COPY . .
9+
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o cmd ./cmd
810

9-
ENTRYPOINT [ "/bin/cmd" ]
11+
# Runtime stage
12+
FROM alpine:latest
13+
14+
RUN apk --no-cache add ca-certificates git
15+
WORKDIR /root/
16+
17+
COPY --from=builder /build/cmd .
18+
19+
ENTRYPOINT ["./cmd"]

README.md

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Automatically update your GitHub profile README with beautiful metrics about you
1111
- 📅 **Commit Patterns** - Visualize when you code most (time of day, day of week)
1212
- 💻 **Language Statistics** - Track programming languages across your repositories
1313
- ⏱️ **WakaTime Integration** - Display coding time, editors, projects and OS usage
14+
- 📈 **Coding Streak Tracker** - Track your coding consistency and streaks with WakaTime
1415
- 🎨 **Customizable** - Choose metrics and customize appearance
1516
- 🔄 **Auto-Updating** - Runs on schedule to keep your profile fresh
1617
- 🚀 **Easy Setup** - Get started in 5 minutes
@@ -83,7 +84,8 @@ jobs:
8384
uses: thanhhaudev/github-stats@master
8485
env:
8586
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
86-
SHOW_METRICS: "COMMIT_TIMES_OF_DAY,COMMIT_DAYS_OF_WEEK,LANGUAGE_PER_REPO"
87+
WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }} # Optional: for WakaTime metrics
88+
SHOW_METRICS: "COMMIT_TIMES_OF_DAY,COMMIT_DAYS_OF_WEEK,LANGUAGE_PER_REPO,CODING_STREAK"
8789
```
8890
### Step 6: Trigger the Action
8991
@@ -100,8 +102,36 @@ Choose which metrics to display by setting the `SHOW_METRICS` environment variab
100102

101103
**Example:**
102104
```yaml
103-
SHOW_METRICS: "COMMIT_TIMES_OF_DAY,COMMIT_DAYS_OF_WEEK,LANGUAGE_PER_REPO"
105+
SHOW_METRICS: "COMMIT_TIMES_OF_DAY,COMMIT_DAYS_OF_WEEK,LANGUAGE_PER_REPO,CODING_STREAK"
104106
```
107+
### 📈 `CODING_STREAK`
108+
109+
Shows your coding streak and consistency metrics combining GitHub commit data with WakaTime statistics.
110+
111+
**Requirements:**
112+
- GitHub commit data (automatically collected) - **Required**
113+
- `WAKATIME_API_KEY` (optional) - Adds coding time statistics
114+
115+
**Example output (with WakaTime):**
116+
117+
**📈 Coding Streak**
118+
```
119+
🔥 Current Streak: 14 days
120+
🏆 Longest Streak: 45 days
121+
📊 Daily Average: 3 hrs 44 mins
122+
💪 Total Coding Time: 1,383 hrs 16 mins
123+
🎯 Coding Consistency: 87.5%
124+
📅 Active Days: 128 days
125+
```
126+
127+
**Example output (without WakaTime):**
128+
```
129+
🔥 Current Streak: 14 days
130+
🏆 Longest Streak: 45 days
131+
```
132+
133+
> 💡 **Note:** Streaks are calculated from your GitHub commit history (consecutive days with at least one commit). The metric respects your `TIME_ZONE` setting for accurate day boundaries. Coding time and consistency metrics are only shown when WakaTime is configured.
134+
105135
106136
### 🕒 `COMMIT_TIMES_OF_DAY`
107137
@@ -207,13 +237,13 @@ Linux 6 hrs 3 mins ████░░░░░░░
207237

208238
**Time range options** (set with `WAKATIME_RANGE`):
209239

210-
| Value | Title Displayed |
211-
|-----------------|-------------------------------------------|
212-
| `last_7_days` | What I Focused On in the Last 7 Days |
213-
| `last_30_days` | How I Spent My Time Over the Last 30 Days |
214-
| `last_6_months` | Where My Time Went in the Last 6 Months |
215-
| `last_year` | My Time Highlights from Last Year |
216-
| `all_time` | How I've Used My Time Across All Time |
240+
| Value | Title Displayed |
241+
|-----------------|--------------------|
242+
| `last_7_days` | 📅 Last 7 Days |
243+
| `last_30_days` | 📊 Last 30 Days |
244+
| `last_6_months` | 📈 Last 6 Months |
245+
| `last_year` | 🗓️ Last 12 Months |
246+
| `all_time` | ⏱️ All Time |
217247

218248
---
219249

@@ -270,7 +300,7 @@ env:
270300
WAKATIME_API_KEY: ${{ secrets.WAKATIME_API_KEY }}
271301
WAKATIME_DATA: "EDITORS,LANGUAGES,PROJECTS,OPERATING_SYSTEMS"
272302
WAKATIME_RANGE: "last_30_days"
273-
SHOW_METRICS: "COMMIT_TIMES_OF_DAY,COMMIT_DAYS_OF_WEEK,LANGUAGE_PER_REPO,LANGUAGES_AND_TOOLS,WAKATIME_SPENT_TIME"
303+
SHOW_METRICS: "COMMIT_TIMES_OF_DAY,COMMIT_DAYS_OF_WEEK,LANGUAGE_PER_REPO,LANGUAGES_AND_TOOLS,WAKATIME_SPENT_TIME,CODING_STREAK"
274304
SHOW_LAST_UPDATE: "true"
275305
ONLY_MAIN_BRANCH: "true"
276306
PROGRESS_BAR_VERSION: "2"

action.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,23 @@ inputs:
5353
runs:
5454
using: docker
5555
image: Dockerfile
56+
env:
57+
GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }}
58+
SHOW_METRICS: ${{ inputs.SHOW_METRICS }}
59+
WAKATIME_API_KEY: ${{ inputs.WAKATIME_API_KEY }}
60+
WAKATIME_DATA: ${{ inputs.WAKATIME_DATA }}
61+
WAKATIME_RANGE: ${{ inputs.WAKATIME_RANGE }}
62+
TIME_ZONE: ${{ inputs.TIME_ZONE }}
63+
TIME_LAYOUT: ${{ inputs.TIME_LAYOUT }}
64+
SHOW_LAST_UPDATE: ${{ inputs.SHOW_LAST_UPDATE }}
65+
ONLY_MAIN_BRANCH: ${{ inputs.ONLY_MAIN_BRANCH }}
66+
HIDE_REPO_INFO: ${{ inputs.HIDE_REPO_INFO }}
67+
COMMIT_MESSAGE: ${{ inputs.COMMIT_MESSAGE }}
68+
COMMIT_USER_NAME: ${{ inputs.COMMIT_USER_NAME }}
69+
COMMIT_USER_EMAIL: ${{ inputs.COMMIT_USER_EMAIL }}
70+
LANGUAGES_AND_TOOLS: ${{ inputs.LANGUAGES_AND_TOOLS }}
71+
EXCLUDE_FORK_REPOS: ${{ inputs.EXCLUDE_FORK_REPOS }}
72+
SIMPLIFY_COMMIT_TIMES_TITLE: ${{ inputs.SIMPLIFY_COMMIT_TIMES_TITLE }}
5673
branding:
5774
icon: 'star'
5875
color: 'orange'

cmd/git.go

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
package main
22

33
import (
4+
"bytes"
45
"fmt"
56
"os"
67
"os/exec"
8+
"regexp"
79
"strings"
810
)
911

1012
// setupGitConfig sets up the git configuration
1113
func setupGitConfig(owner, token, name, email string) error {
14+
hideRepoInfo := os.Getenv("HIDE_REPO_INFO") == "true"
15+
1216
if name == "" {
1317
name = "GitHub Action"
1418
}
@@ -17,21 +21,21 @@ func setupGitConfig(owner, token, name, email string) error {
1721
email = "action@github.com"
1822
}
1923

20-
if err := runGitCommand("config", "--global", "--add", "safe.directory", "/github/workspace"); err != nil {
21-
return fmt.Errorf("git config safe.directory error: %v", err)
24+
if err := runGitCommand(hideRepoInfo, "config", "--global", "--add", "safe.directory", "/github/workspace"); err != nil {
25+
return fmt.Errorf("git config safe.directory error: %v", sanitizeError(err, token, owner))
2226
}
2327

24-
if err := runGitCommand("config", "--global", "user.name", name); err != nil {
25-
return fmt.Errorf("git config user.name error: %v", err)
28+
if err := runGitCommand(hideRepoInfo, "config", "--global", "user.name", name); err != nil {
29+
return fmt.Errorf("git config user.name error: %v", sanitizeError(err, token, owner))
2630
}
2731

28-
if err := runGitCommand("config", "--global", "user.email", email); err != nil {
29-
return fmt.Errorf("git config user.email error: %v", err)
32+
if err := runGitCommand(hideRepoInfo, "config", "--global", "user.email", email); err != nil {
33+
return fmt.Errorf("git config user.email error: %v", sanitizeError(err, token, owner))
3034
}
3135

3236
remoteURL := fmt.Sprintf("https://%s@github.com/%s/%s.git", token, owner, owner)
33-
if err := runGitCommand("remote", "set-url", "origin", remoteURL); err != nil {
34-
return fmt.Errorf("git remote set-url error: %v", err)
37+
if err := runGitCommand(hideRepoInfo, "remote", "set-url", "origin", remoteURL); err != nil {
38+
return fmt.Errorf("git remote set-url error: %v", sanitizeError(err, token, owner))
3539
}
3640

3741
return nil
@@ -50,6 +54,8 @@ func hasReadmeChanged() (bool, error) {
5054

5155
// commitAndPushReadme Commit and push changes if README.md has changed
5256
func commitAndPushReadme(msg, branch string) error {
57+
hideRepoInfo := os.Getenv("HIDE_REPO_INFO") == "true"
58+
5359
if branch == "" {
5460
branch = "main"
5561
}
@@ -58,24 +64,65 @@ func commitAndPushReadme(msg, branch string) error {
5864
msg = "📝 Update README.md"
5965
}
6066

61-
if err := runGitCommand("add", "README.md"); err != nil {
67+
if err := runGitCommand(hideRepoInfo, "add", "README.md"); err != nil {
6268
return err
6369
}
6470

65-
if err := runGitCommand("commit", "-m", msg); err != nil {
71+
if err := runGitCommand(hideRepoInfo, "commit", "-m", msg); err != nil {
6672
return err
6773
}
6874

69-
return runGitCommand("push", "origin", branch)
75+
return runGitCommand(hideRepoInfo, "push", "origin", branch)
7076
}
7177

72-
func runGitCommand(args ...string) error {
78+
func runGitCommand(hideRepoInfo bool, args ...string) error {
7379
cmd := exec.Command("git", args...)
74-
cmd.Stdout = os.Stdout
75-
cmd.Stderr = os.Stderr
76-
if err := cmd.Run(); err != nil {
77-
return fmt.Errorf("failed to run 'git %v': %v", args, err)
80+
81+
if hideRepoInfo {
82+
// Suppress output when HIDE_REPO_INFO is true to prevent leaking sensitive information
83+
var stdout, stderr bytes.Buffer
84+
cmd.Stdout = &stdout
85+
cmd.Stderr = &stderr
86+
87+
if err := cmd.Run(); err != nil {
88+
// Sanitize error output before returning
89+
sanitizedErr := strings.ReplaceAll(err.Error(), stdout.String(), "[output hidden]")
90+
sanitizedErr = strings.ReplaceAll(sanitizedErr, stderr.String(), "[output hidden]")
91+
return fmt.Errorf("failed to run git command: %v", sanitizedErr)
92+
}
93+
} else {
94+
cmd.Stdout = os.Stdout
95+
cmd.Stderr = os.Stderr
96+
if err := cmd.Run(); err != nil {
97+
return fmt.Errorf("failed to run 'git %v': %v", args, err)
98+
}
7899
}
79100

80101
return nil
81102
}
103+
104+
// sanitizeError removes sensitive information from error messages
105+
func sanitizeError(err error, token, owner string) error {
106+
if err == nil {
107+
return nil
108+
}
109+
110+
errMsg := err.Error()
111+
112+
// Replace token with placeholder
113+
if token != "" {
114+
errMsg = strings.ReplaceAll(errMsg, token, "[***]")
115+
}
116+
117+
// Replace owner/username with placeholder
118+
if owner != "" {
119+
errMsg = strings.ReplaceAll(errMsg, owner, "[***]")
120+
}
121+
122+
// Replace URLs with regex to redact entire URLs (http/https)
123+
// Matches: http(s)://anything until whitespace or end of string
124+
urlRegex := regexp.MustCompile(`https?://[^\s]+`)
125+
errMsg = urlRegex.ReplaceAllString(errMsg, "[***]")
126+
127+
return fmt.Errorf("%s", errMsg)
128+
}

0 commit comments

Comments
 (0)