|
| 1 | +name: 🔄 Update README with Onefetch |
| 2 | + |
| 3 | +on: |
| 4 | + push: |
| 5 | + branches: |
| 6 | + - main |
| 7 | + - master |
| 8 | + schedule: |
| 9 | + - cron: "0 0 * * 0" |
| 10 | + workflow_dispatch: |
| 11 | + |
| 12 | +permissions: |
| 13 | + contents: write |
| 14 | + |
| 15 | +jobs: |
| 16 | + update-readme: |
| 17 | + name: Gerar Onefetch e atualizar README |
| 18 | + runs-on: ubuntu-latest |
| 19 | + |
| 20 | + steps: |
| 21 | + - name: 📥 Checkout do repositório |
| 22 | + uses: actions/checkout@v4 |
| 23 | + with: |
| 24 | + fetch-depth: 0 |
| 25 | + |
| 26 | + - name: 🦀 Instalar Onefetch |
| 27 | + run: | |
| 28 | + VERSION=$(curl -s https://api.github.com/repos/o2sh/onefetch/releases/latest \ |
| 29 | + | python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'])") |
| 30 | + curl -sL "https://github.com/o2sh/onefetch/releases/download/${VERSION}/onefetch_amd64.deb" \ |
| 31 | + -o onefetch.deb |
| 32 | + sudo dpkg -i onefetch.deb |
| 33 | +
|
| 34 | + - name: 🧊 Instalar Freeze |
| 35 | + run: | |
| 36 | + go install github.com/charmbracelet/freeze@latest |
| 37 | + echo "$(go env GOPATH)/bin" >> $GITHUB_PATH |
| 38 | +
|
| 39 | + - name: 🎨 Gerar SVG com onefetch + freeze |
| 40 | + run: | |
| 41 | + # FIX CORES: script cria pseudo-TTY sem pacotes extras |
| 42 | + # onefetch mantém cores ANSI reais dentro de um TTY |
| 43 | + script -q -c "onefetch -d pending" /dev/null \ |
| 44 | + | freeze --language ansi --theme none --output onefetch.svg |
| 45 | +
|
| 46 | + - name: 📊 Adicionar barra de linguagens ao SVG |
| 47 | + run: | |
| 48 | + onefetch --output json -d pending > /tmp/onefetch.json 2>/dev/null || echo "{}" > /tmp/onefetch.json |
| 49 | +
|
| 50 | + python3 << 'PYEOF' |
| 51 | + import json, re |
| 52 | +
|
| 53 | + LANG_COLORS = { |
| 54 | + 'python':'#3572A5','javascript':'#f1e05a','typescript':'#2b7489', |
| 55 | + 'rust':'#dea584','go':'#00ADD8','java':'#b07219','c':'#555555', |
| 56 | + 'c++':'#f34b7d','c#':'#178600','ruby':'#701516','php':'#4F5D95', |
| 57 | + 'swift':'#ffac45','kotlin':'#A97BFF','dart':'#00B4AB','scala':'#c22d40', |
| 58 | + 'html':'#e34c26','css':'#563d7c','shell':'#89e051','bash':'#89e051', |
| 59 | + 'yaml':'#cb171e','vue':'#41b883','svelte':'#ff3e00','r':'#198CE7', |
| 60 | + } |
| 61 | +
|
| 62 | + def lang_color(name): return LANG_COLORS.get(name.lower(), '#8b949e') |
| 63 | +
|
| 64 | + def lang_info(l): |
| 65 | + if isinstance(l, list): return l[0], float(l[1]) if len(l)>1 else 0 |
| 66 | + if isinstance(l, dict): return l.get('name','?'), float(l.get('percentage', 0)) |
| 67 | + return str(l), 0 |
| 68 | +
|
| 69 | + with open('/tmp/onefetch.json') as f: |
| 70 | + data = json.load(f) |
| 71 | + languages = data.get('languages', []) |
| 72 | +
|
| 73 | + with open('onefetch.svg') as f: |
| 74 | + svg = f.read() |
| 75 | +
|
| 76 | + w_match = re.search(r'<svg[^>]+width=["\']([0-9.]+)', svg) |
| 77 | + h_match = re.search(r'<svg[^>]+height=["\']([0-9.]+)', svg) |
| 78 | + svg_w = int(float(w_match.group(1))) if w_match else 800 |
| 79 | + svg_h = int(float(h_match.group(1))) if h_match else 400 |
| 80 | +
|
| 81 | + PAD, BAR_H, LEG_H = 20, 10, 20 |
| 82 | + ROWS = max(1, (len(languages) + 3) // 4) |
| 83 | + BAR_BLOCK_H = PAD + BAR_H + PAD//2 + ROWS * LEG_H + PAD |
| 84 | + total_h = svg_h + BAR_BLOCK_H |
| 85 | + bar_w = svg_w - PAD * 2 |
| 86 | +
|
| 87 | + parts = [ |
| 88 | + f' <g transform="translate(0,{svg_h})">', |
| 89 | + f' <rect width="{svg_w}" height="{BAR_BLOCK_H}" fill="#0d1117"/>', |
| 90 | + f' <rect x="{PAD}" y="{PAD}" width="{bar_w}" height="{BAR_H}" rx="5" fill="#21262d"/>', |
| 91 | + ] |
| 92 | +
|
| 93 | + total_pct = sum(lang_info(l)[1] for l in languages) or 1 |
| 94 | + cx = PAD |
| 95 | + for lang in languages: |
| 96 | + name, pct = lang_info(lang) |
| 97 | + w = int((pct / total_pct) * bar_w) |
| 98 | + if w > 0: |
| 99 | + parts.append(f' <rect x="{cx}" y="{PAD}" width="{w}" height="{BAR_H}" rx="3" fill="{lang_color(name)}"/>') |
| 100 | + cx += w |
| 101 | +
|
| 102 | + lx = PAD |
| 103 | + ly = PAD + BAR_H + PAD//2 + LEG_H |
| 104 | + for lang in languages: |
| 105 | + name, pct = lang_info(lang) |
| 106 | + color = lang_color(name) |
| 107 | + label = f'{name.replace("&","&").replace("<","<").replace("+","+").replace("#","#")} {pct:.1f}%' |
| 108 | + parts.append(f' <circle cx="{lx+5}" cy="{ly-5}" r="5" fill="{color}"/>') |
| 109 | + parts.append(f' <text x="{lx+14}" y="{ly}" font-family="Courier New,monospace" font-size="12px" fill="#c9d1d9">{label}</text>') |
| 110 | + lx += len(name) * 7.5 + 60 |
| 111 | + if lx > svg_w - 100: |
| 112 | + lx = PAD; ly += LEG_H |
| 113 | +
|
| 114 | + parts.append(' </g>') |
| 115 | +
|
| 116 | + new_svg = svg.replace('</svg>', '\n'.join(parts) + '\n</svg>') |
| 117 | + new_svg = re.sub(r'(<svg[^>]+height=["\'])([0-9.]+)', lambda m: m.group(1) + str(total_h), new_svg, count=1) |
| 118 | +
|
| 119 | + with open('onefetch.svg', 'w') as f: |
| 120 | + f.write(new_svg) |
| 121 | + print(f"SVG final: {svg_w}x{total_h}px | {len(languages)} linguagens") |
| 122 | + PYEOF |
| 123 | +
|
| 124 | + - name: 📝 Atualizar README.md |
| 125 | + run: | |
| 126 | + python3 << 'EOF' |
| 127 | + import re |
| 128 | + try: |
| 129 | + with open("README.md","r",encoding="utf-8") as f: readme = f.read() |
| 130 | + except FileNotFoundError: |
| 131 | + readme = "" |
| 132 | + new_block = "<!-- ONEFETCH_START -->\n\n<!-- ONEFETCH_END -->" |
| 133 | + pattern = r"<!-- ONEFETCH_START -->.*?<!-- ONEFETCH_END -->" |
| 134 | + if re.search(pattern, readme, re.DOTALL): |
| 135 | + updated = re.sub(pattern, new_block, readme, flags=re.DOTALL) |
| 136 | + else: |
| 137 | + updated = readme.rstrip() + "\n\n" + new_block + "\n" |
| 138 | + with open("README.md","w",encoding="utf-8") as f: f.write(updated) |
| 139 | + print("README.md atualizado!") |
| 140 | + EOF |
| 141 | +
|
| 142 | + - name: 🔍 Verificar mudanças |
| 143 | + id: check_changes |
| 144 | + run: | |
| 145 | + if git diff --quiet README.md onefetch.svg; then |
| 146 | + echo "changed=false" >> $GITHUB_OUTPUT |
| 147 | + else |
| 148 | + echo "changed=true" >> $GITHUB_OUTPUT |
| 149 | + fi |
| 150 | +
|
| 151 | + - name: 💾 Commit e Push |
| 152 | + if: steps.check_changes.outputs.changed == 'true' |
| 153 | + run: | |
| 154 | + git config --local user.email "github-actions[bot]@users.noreply.github.com" |
| 155 | + git config --local user.name "github-actions[bot]" |
| 156 | + git add README.md onefetch.svg |
| 157 | + git commit -m "docs: atualiza estatísticas do repo via onefetch [skip ci]" |
| 158 | + git push |
0 commit comments