Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions .github/workflows/devchart-fetcher-flow.yaml
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
name: DevChart Data Fetcher Action
name: "DevChart Data Fetcher Action"
on:
workflow_dispatch:

jobs:
job-crawler:
runs-on: ubuntu-latest
name: Run fetcher
runs-on: "ubuntu-latest"
name: "Run fetcher"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Fetch data
id: fetch-data
uses: ./actions # Uses an action in the actions directory
- name: "Checkout"
uses: "actions/checkout@v4"
- name: "Fetch data"
id: "fetch-data"
uses: "./actions" # Uses an action in the actions directory
with:
username_github: ${{ vars.username_github }}
username_leetcode: ${{ vars.username_leetcode }}
- name: Print run_at
run: echo "${{ steps.fetch-data.outputs.run_at }}"
username_github: "${{ vars.username_github }}"
username_leetcode: "${{ vars.username_leetcode }}"
- name: "Print run_at"
run: "echo ${{ steps.fetch-data.outputs.run_at }}"

- name: Commit and push if it changed
- name: "Commit and push if it changed"
run: |
git config --global user.name 'DevChart APIs'
git config --global user.email 'action@github.com'
git add -A
git diff --quiet && git diff --staged --quiet || git commit -m "DevChart data update"
git push
git diff --quiet && git diff --staged --quiet || git commit -m 'DevChart data update'
git push
22 changes: 11 additions & 11 deletions actions/action.yaml
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
name: 'DevChart Retention'
description: 'This Action is designed to store GitHub or Leetcode chart data in JSON and SVG format, push it into public repostiory and make use for your own website or blog.'
name: "DevChart Retention"
description: "This Action is designed to store GitHub or Leetcode chart data in JSON and SVG format, push it into public repostiory and make use for your own website or blog."
branding:
icon: 'upload-cloud'
color: 'blue'
icon: "upload-cloud"
color: "blue"
inputs:
username_github:
description: 'GitHub username for getting contribution chart data'
description: "GitHub username for getting contribution chart data"
required: true
username_leetcode:
description: 'Leetcode username for getting contribution chart data'
description: "Leetcode username for getting contribution chart data"
required: true

outputs:
run_at:
description: 'Run time'
description: "Run time"
value: ${{ steps.fetch-data.outputs.run_at }}

runs:
using: 'composite'
using: "composite"
steps:
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: '3.11.9'
cache: 'pip'
python-version: "3.11.9"
cache: "pip"
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
Expand All @@ -37,4 +37,4 @@ runs:
- name: Fetch data
id: fetch-data
run: python actions/fetcher.py --run_mode github_action
shell: bash
shell: bash
77 changes: 40 additions & 37 deletions actions/fetcher.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,41 @@
import os
import argparse
import sys
from datetime import datetime
import matplotlib.pyplot as plt
import libs.stats as stats
from heatmap_chart import generate_heatmap

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

RUN_MODE = ['local', 'github_action']
RUN_MODES = ['local', 'github_action']
parser = argparse.ArgumentParser(description='Dev Chart Fetcher')
parser.add_argument('--run_mode', action="store", dest='run_mode', default='github_action')
parser.add_argument('--username_github', action="store", dest='username_github', default=None)
parser.add_argument('--username_leetcode', action="store", dest='username_leetcode', default=None)

args = parser.parse_args()
if args.run_mode not in RUN_MODE:
if args.run_mode not in RUN_MODES:
raise ValueError('Invalid run_mode, accepted: local, github_action')

if args.run_mode == 'github_action':
USERNAME_GITHUB = os.environ.get("username_github")
if USERNAME_GITHUB:
print(f'username_github: {USERNAME_GITHUB}')
GITHUB_USERNAME = os.environ.get("username_github")
if GITHUB_USERNAME:
print(f'username_github: {GITHUB_USERNAME}')
else:
print('WARNING: username_github not provided')

USERNAME_LEETCODE = os.environ.get("username_leetcode")
if USERNAME_LEETCODE:
print(f'username_leetcode: {USERNAME_LEETCODE}')
LEETCODE_USERNAME = os.environ.get("username_leetcode")
if LEETCODE_USERNAME:
print(f'username_leetcode: {LEETCODE_USERNAME}')
else:
print('WARNING: username_leetcode not provided')

elif args.run_mode == 'local':
USERNAME_GITHUB = args.username_github
USERNAME_LEETCODE = args.username_leetcode

from datetime import datetime
print(f"::set-output name=run_at::{datetime.now().isoformat()}Z")

import libs.stats as stats
from heatmap_chart import generate_heatmap
elif args.run_mode == 'local':
GITHUB_USERNAME = args.username_github
LEETCODE_USERNAME = args.username_leetcode

import matplotlib.pyplot as plt
print(f"::set-output name=run_at::{datetime.now().isoformat()}Z")

STYLES = ['dark_background', 'default']
THEME_MODES = ['dark', 'light']
Expand All @@ -46,40 +45,44 @@
os.makedirs(ASSETS_DIR)

def fetch_github():
if not USERNAME_GITHUB:
"""
Fetch GitHub contribution data and generate heatmap SVGs.
"""
if not GITHUB_USERNAME:
return

print(f'USERNAME_GITHUB: {USERNAME_GITHUB}')
print(f'GITHUB_USERNAME: {GITHUB_USERNAME}')

github_data = stats.get_github_contribution(GITHUB_USERNAME)

json = stats.get_github_contribution(USERNAME_GITHUB)

for i in range(len(STYLES)):
plt.style.use(STYLES[i])
generate_heatmap(USERNAME_GITHUB, json)
generate_heatmap(GITHUB_USERNAME, github_data)
plt.savefig(f'{ASSETS_DIR}/github_{THEME_MODES[i]}.svg', format='svg', bbox_inches='tight', transparent=True)

return

def fetch_leetcode():
if not USERNAME_LEETCODE:
"""
Fetch LeetCode submission data and generate heatmap SVGs.
"""
if not LEETCODE_USERNAME:
return

print(f'USERNAME_LEETCODE: {USERNAME_LEETCODE}')
print(f'LEETCODE_USERNAME: {LEETCODE_USERNAME}')

leetcode_data = stats.get_leetcode_submission(LEETCODE_USERNAME)

json = stats.get_leetcode_submission(USERNAME_LEETCODE)

for i in range(len(STYLES)):
plt.style.use(STYLES[i])
generate_heatmap(USERNAME_LEETCODE, json)
generate_heatmap(LEETCODE_USERNAME, leetcode_data)
plt.savefig(f'{ASSETS_DIR}/leetcode_{THEME_MODES[i]}.svg', format='svg', bbox_inches='tight', transparent=True)

return


def __main__():
print('Fetching Github and Leetcode data...')
def main():
"""
Main function to fetch GitHub and LeetCode data.
"""
print('Fetching GitHub and LeetCode data...')
fetch_github()
fetch_leetcode()

__main__()

if __name__ == "__main__":
main()
64 changes: 58 additions & 6 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,29 @@

@app.route('/api/github/<username>/json')
def get_github_stats_json(username):
json = stats.get_github_contribution(username)
return jsonify(json), 200, {'Content-Type': 'application/json'}
"""
Get GitHub contribution stats in JSON format.

Args:
username (str): GitHub username.

Returns:
Response: JSON response containing GitHub contribution stats.
"""
json_data = stats.get_github_contribution(username)
return jsonify(json_data), 200, {'Content-Type': 'application/json'}

def generate_calendar_chart(username, stats_function):
"""
Generate a calendar chart for the given username using the specified stats function.

Args:
username (str): Username for which to generate the chart.
stats_function (function): Function to fetch stats for the given username.

Returns:
Response: SVG response containing the generated calendar chart.
"""
mode = request.args.get('mode', default='prod')
theme_mode = request.args.get('theme_mode', default='light')

Expand All @@ -29,7 +48,7 @@ def generate_calendar_chart(username, stats_function):
if theme_mode not in ['dark', 'light']:
return jsonify({'error': 'Invalid theme_mode, accepted: dark, light'}), 400, {'Content-Type': 'application/json'}

json = stats_function(username)
json_data = stats_function(username)

background_color = ''
if theme_mode == 'dark':
Expand All @@ -42,7 +61,7 @@ def generate_calendar_chart(username, stats_function):
# Create a buffer to save the plot
buffer = io.BytesIO()

generate_heatmap(username, json)
generate_heatmap(username, json_data)

plt.savefig(buffer, backend='svg', format='svg', bbox_inches='tight', transparent=True)
plt.close()
Expand All @@ -61,22 +80,55 @@ def generate_calendar_chart(username, stats_function):

@app.route('/api/github/<username>/svg')
def get_github_stats_svg(username):
"""
Get GitHub contribution stats in SVG format.

Args:
username (str): GitHub username.

Returns:
Response: SVG response containing GitHub contribution stats.
"""
return generate_calendar_chart(username, stats.get_github_contribution)


@app.route('/api/leetcode/<username>/json')
def get_leetcode_stats_json(username):
json = stats.get_leetcode_submission(username)
return jsonify(json), 200, {'Content-Type': 'application/json'}
"""
Get LeetCode submission stats in JSON format.

Args:
username (str): LeetCode username.

Returns:
Response: JSON response containing LeetCode submission stats.
"""
json_data = stats.get_leetcode_submission(username)
return jsonify(json_data), 200, {'Content-Type': 'application/json'}


@app.route('/api/leetcode/<username>/svg')
def get_leetcode_stats_svg(username):
"""
Get LeetCode submission stats in SVG format.

Args:
username (str): LeetCode username.

Returns:
Response: SVG response containing LeetCode submission stats.
"""
return generate_calendar_chart(username, stats.get_leetcode_submission)

# Load Browser Favorite Icon
@app.route('/favicon.ico')
def favicon():
"""
Serve the favicon.

Returns:
Response: Favicon image.
"""
return url_for('static', filename='image/favicon.png')

if __name__ == '__main__':
Expand Down
12 changes: 7 additions & 5 deletions july/helpers.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import calendar
import numpy as np
from datetime import date
from typing import List, Any, Optional, Union

import matplotlib.pyplot as plt
from july.colormaps import cmaps_dict
from matplotlib.pyplot import Axes
import numpy as np
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
from matplotlib.pyplot import Axes
from matplotlib.ticker import ScalarFormatter
from typing import List, Any, Optional, Union
from datetime import date

from july.colormaps import cmaps_dict


def date_grid(
Expand Down
8 changes: 5 additions & 3 deletions july/plot.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import numpy as np
import calendar
import datetime
import matplotlib.pyplot as plt
from typing import List, Any, Optional, Union, Tuple
from matplotlib.pyplot import Axes

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import LinearSegmentedColormap, ListedColormap
from matplotlib.pyplot import Axes

from july.helpers import (
date_grid,
cal_heatmap,
Expand Down
Loading