Yasin Ateş
5 dk Medium

GitHub Profil README’ni Canlı Tut: GitHub Actions ile Otomatik Güncelleme Rehberi⚡

GitHub Profil README’ni Canlı Tut: GitHub Actions ile Otomatik Güncelleme Rehberi⚡
Github Profil README Dinamik Hale Getirme

GitHub profilinize giren biri sizi tanımak ister. Kim olduğunuzu, neler yaptığınızı, neler yazdığınızı görmek ister. Ama çoğu profil README'si bir kere yazılır, sonra yıllarca öylece durur. 2021'den kalma "latest posts" listesi, süresi geçmiş projeler, hâlâ güncellenmeyi bekleyen teknoloji stack'i.

Peki ya README'niz her sabah kendi kendini güncelleseydi?

Bu yazıda Medium ve dev.to makalelerinizi otomatik olarak çeken, GitHub Actions ile her gün çalışan ve README'nizi canlı tutan bir sistem kuracağız. Python scriptten workflow dosyasına, placeholder marker'lardan manuel tetiklemeye kadar her adımı tek tek inceleyeceğiz.

1. Nasıl Çalışır? 🔄

Github Actions İle Otomatik Güncellenen Profil README

Kuracağımız sistem dört parçadan oluşuyor:

README.md içine özel HTML yorum satırları (<!-- MEDIUM-ARTICLES:START --> gibi) yerleştiriyoruz. Script bu marker'lar arasındaki içeriği bulup değiştiriyor; marker'ların dışındaki hiçbir şeye dokunmuyor.

Python scripti Medium'un RSS feed'ini ve dev.to'nun REST API'sini çağırıyor, makale başlıklarını ve URL'lerini topluyor, ardından README'yi güncelliyor.

GitHub Actions workflow'u bu scripti zamanlanmış olarak çalıştırıyor. Her gün sabah 06:00 UTC'de tetikleniyor; script bir değişiklik yapıyorsa otomatik olarak commit atıp push ediyor.

Manuel tetikleme seçeneği sayesinde beklemek zorunda kalmıyorsunuz. Yeni bir makale yayınladığınız an Actions sekmesinden tek tıkla çalıştırabiliyorsunuz.

💡 Sistem tamamen GitHub'ın kendi altyapısında çalışır. Harici bir sunucuya, ücretli bir servise veya kendi makinenizin açık olmasına ihtiyaç yoktur. GitHub Actions, public repolar için ücretsizdir.

2. GitHub Profil README'si Nedir? 👤

Github kullanıcı adı ile aynı Repository olunca ne olur?

GitHub, kullanıcı adınızla aynı isimde bir repo oluşturduğunuzda içindeki README.md dosyasını otomatik olarak profil sayfanızda gösterir. Bu özel bir GitHub özelliğidir.

Github Profil README’si Nasıl Oluşturulur?

  1. GitHub'da New repository butonuna tıklayın
  2. Repository name olarak kendi kullanıcı adınızı yazın (örneğin yasinatesim)
  3. Public seçili olsun
  4. Add a README file kutucuğunu işaretleyin
  5. Create repository butonuna tıklayın

Repo oluşturduğunuzda GitHub sizi "✨ yasinatesim/yasinatesim is a special repository" mesajıyla karşılar. README.md dosyasına yazdığınız her şey profilinizde görünmeye başlar.

⚠️ Repository adı Github kullanıcı adınızla birebir aynı olmalıdır, büyük/küçük harf dahil.

3. Github Profil README'ye Placeholder Marker Eklemek 📍

Github Profil Readme dosyasına dinamik içerik için alan ekleme

Script README'de neyi güncelleyeceğini nasıl biliyor? HTML yorum satırları ile koyduğumuz özel marker'lar sayesinde. Bu marker'lar tarayıcıda veya GitHub'da görünmez, ama script için birer koordinat görevi görür.

README'nizin makaleleri göstermesini istediğiniz yerine şu bloğu ekleyin:

1## ✍️ Latest Medium Articles
2
3<!-- MEDIUM-ARTICLES:START -->
4<!-- MEDIUM-ARTICLES:END -->
5
6## 📝 Latest dev.to Articles
7
8<!-- DEVTO-ARTICLES:START -->
9<!-- DEVTO-ARTICLES:END -->

Script çalıştığında bu iki marker arasındaki her şeyi siler ve yerine güncel makale listesini yazar. Marker'ların dışındaki hiçbir satıra dokunmaz. İlk çalıştırmadan sonra görünüm şöyle olacak;

1## ✍️ Latest Medium Articles
2
3<!-- MEDIUM-ARTICLES:START -->
4- [Micro Frontend Mimarisi (React Örnekleriyle)](https://medium.com/...)
5- [Google Lighthouse'u Yazılım Geliştirme Sürecimize Nasıl Entegre Ettik?](https://medium.com/...) *(Hepsiburadatech)*
6- [A'dan Z'ye Typescript](https://medium.com/...)
7<!-- MEDIUM-ARTICLES:END -->
💡 Yukarıdaki örnek kendi Github Profil README dosyama ait.
Publication bilgisi (parantez içindeki kanal adı) script tarafından makale URL'sinden otomatik çıkarılır. medium.com/publication/... gibi bir URL'yi görünce slug'ı alıp parantez içinde makale başlığının yanına ekler (Yukarıdaki çıktıdaki 2. Satırda bunu gösterdim).
Kişisel profil yazıları için (medium.com/@yasinatesim/...) parantez göstermez.

4. Python Script: Makale Verilerini Çekmek 🐍

Py Scripti ile Medium ve dev.to verilerini çekme ve birleştirme

Scriptin tamamı iki harici kütüphane kullanıyor: feedparser (Medium RSS için) ve requests (dev.to API için). Başka hiçbir bağımlılık yok.

1scripts/
2└── fetch_articles.py

4.1 Temel Yapı

1"""
2fetch_articles.py
3-----------------
4Medium RSS ve dev.to API'sinden tüm makaleleri çeker,
5README.md içindeki placeholder'ları otomatik günceller.
6"""
7
8import re
9import feedparser
10import requests
11
12MEDIUM_USERNAME = "kullanici-adiniz"   # @ işareti olmadan
13DEVTO_USERNAME  = "kullanici-adiniz"
14README_PATH     = "README.md"
15
16MEDIUM_START = "<!-- MEDIUM-ARTICLES:START -->"
17MEDIUM_END   = "<!-- MEDIUM-ARTICLES:END -->"
18DEVTO_START  = "<!-- DEVTO-ARTICLES:START -->"
19DEVTO_END    = "<!-- DEVTO-ARTICLES:END -->"

4.2 Medium Makalelerini Çekmek

Medium her kullanıcı için herkese açık bir RSS feed sunar. feedparser bu XML feed'i Python objelerine dönüştürür. Limit koymuyoruz; feed.entries listesinin tamamını işliyoruz.

1def fetch_medium_articles():
2    url  = f"https://medium.com/feed/@{MEDIUM_USERNAME}"
3    feed = feedparser.parse(url)
4    articles = []
5
6    for entry in feed.entries:
7        publication = None
8        link = entry.link
9
10        # URL'den publication bilgisini çıkar
11        # medium.com/publication-slug/... → publication var
12        # medium.com/@username/...        → kişisel profil, publication yok
13        subdomain_match = re.match(r"https://([^.]+)\.medium\.com/", link)
14        path_match      = re.match(r"https://medium\.com/([^@/][^/]*)/", link)
15
16        if subdomain_match:
17            slug = subdomain_match.group(1)
18            publication = slug.replace("-", " ").title()
19        elif path_match:
20            slug = path_match.group(1)
21            # Sistem path'lerini filtrele (tag, search, topic vb.)
22            system_paths = {"tag", "tags", "search", "topic", "topics",
23                            "m", "about", "membership"}
24            if slug not in system_paths:
25                publication = slug.replace("-", " ").title()
26
27        articles.append({
28            "title":       entry.title,
29            "url":         link,
30            "publication": publication,
31        })
32
33    return articles
⚠️ Medium RSS feed'i varsayılan olarak son 10 makaleyi döndürür. Bu Medium'un koyduğu bir kısıtlamadır; scriptiniz ne kadar uğraşırsa uğraşsın 10'dan fazlasını RSS üzerinden çekemez. Tüm makalelerinizi göstermek istiyorsanız scraping yöntemlerini araştırmanız gerekir.

Şuan benim Medium’da yayınlanmış 10 tane makalen olmadığı için henüz kendi Github Profil README dosyama entegrasyon sağlamadım. 😁 10 makaleyi geçtikten sonra Github reposunu güncellerim. Repo linki makale sonundaki “Demo” kısmında

4.3 dev.to Makalelerini Çekmek

dev.to'nun açık bir REST API'si var ve API anahtarı gerektirmiyor. Sayfalama desteği olduğundan while döngüsüyle tüm makaleleri çekebiliyoruz:

1def fetch_devto_articles():
2    page, articles = 1, []
3
4    while True:
5        url = (
6            f"https://dev.to/api/articles"
7            f"?username={DEVTO_USERNAME}&per_page=100&page={page}"
8        )
9        response = requests.get(url, timeout=10)
10
11        if response.status_code != 200:
12            break
13
14        batch = response.json()
15        if not batch:          # Boş sayfa → veri bitti
16            break
17
18        for item in batch:
19            articles.append({
20                "title": item["title"],
21                "url":   item["url"],
22            })
23
24        page += 1
25
26    return articles

4.4 Markdown Satırlarını Oluşturmak

1def build_medium_rows(articles):
2    if not articles:
3        return "_No articles found._"
4
5    rows = []
6    for a in articles:
7        # Publication varsa italik parantez içinde göster
8        pub = f" *({a['publication']})*" if a.get("publication") else ""
9        rows.append(f'- [{a["title"]}]({a["url"]}){pub}')
10
11    return "\n".join(rows)
12
13
14def build_devto_rows(articles):
15    if not articles:
16        return "_No articles found._"
17
18    return "\n".join(
19        f'- [{a["title"]}]({a["url"]})' for a in articles
20    )

4.5 README'yi Güncellemek

Regex ile marker'lar arasındaki bloğu bulup yeni içerikle değiştiriyoruz. re.DOTALL flag'i . karakterinin yeni satırları da eşlemesini sağlıyor; bu olmadan çok satırlı bloklar yakalanmaz.

1def replace_section(content, start_marker, end_marker, new_body):
2    pattern = re.compile(
3        rf"{re.escape(start_marker)}.*?{re.escape(end_marker)}",
4        re.DOTALL,
5    )
6    replacement = f"{start_marker}\n{new_body}\n{end_marker}"
7    return pattern.sub(replacement, content)
8
9
10def main():
11    print("📡 Fetching Medium articles...")
12    medium_articles = fetch_medium_articles()
13    print(f"   ✅ {len(medium_articles)} articles fetched.")
14
15    print("📡 Fetching dev.to articles...")
16    devto_articles = fetch_devto_articles()
17    print(f"   ✅ {len(devto_articles)} articles fetched.")
18
19    with open(README_PATH, "r", encoding="utf-8") as f:
20        content = f.read()
21
22    content = replace_section(
23        content, MEDIUM_START, MEDIUM_END, build_medium_rows(medium_articles)
24    )
25    content = replace_section(
26        content, DEVTO_START, DEVTO_END, build_devto_rows(devto_articles)
27    )
28
29    with open(README_PATH, "w", encoding="utf-8") as f:
30        f.write(content)
31
32    print("✅ README.md updated successfully!")
33
34
35if __name__ == "__main__":
36    main()

5. GitHub Actions Workflow Dosyası ⚙️

Github Workflow Akışı

Workflow dosyası .github/workflows/ klasörü altına konur. GitHub bu klasörü otomatik olarak tarar ve YAML dosyalarını workflow olarak işler.

1.github/
2└── workflows/
3    └── update-articles.yml

Dosya içeriği;

1name: 📝 Update Blog Articles
2
3on:
4  schedule:
5    - cron: "0 6 * * *"   # Her gün 06:00 UTCTürkiye saatiyle 09:00
6  workflow_dispatch:        # Actions sekmesinden manuel tetikleme için
7
8jobs:
9  update-readme:
10    name: Fetch & Update Articles
11    runs-on: ubuntu-latest
12
13    steps:
14      - name: 🔄 Checkout Repository
15        uses: actions/checkout@v4
16
17      - name: 🐍 Set up Python
18        uses: actions/setup-python@v5
19        with:
20          python-version: "3.11"
21
22      - name: 📦 Install Dependencies
23        run: pip install requests feedparser
24
25      - name: 🚀 Run Article Fetcher
26        run: python scripts/fetch_articles.py
27
28      - name: 💾 Commit & Push Changes
29        run: |
30          git config --local user.email "github-actions[bot]@users.noreply.github.com"
31          git config --local user.name "github-actions[bot]"
32          git add README.md
33          git diff --staged --quiet || git commit -m "📝 Auto-update: Latest blog articles [$(date +'%Y-%m-%d')]"
34          git push

actions/checkout@v4 — Workflow'un çalıştığı sanal makineye (ubuntu-latest) reponuzu kopyalar. Olmadan script README.md'yi bulamaz.

actions/setup-python@v5 — Python 3.11 ortamını kurar. GitHub Actions makinelerinde Python önceden kurulu olsa da versiyonu sabitlemek daha güvenlidir.

pip install requests feedparser — İki bağımlılığı kurar.

python scripts/fetch_articles.py — Scripti çalıştırır. Bu adım README.md dosyasını günceller ama henüz commit atmaz.

Commit & Push adımı

1git diff --staged --quiet || git commit -m "..."

git diff --staged --quiet README'de değişiklik yoksa “sıfır” döndürür yani “exit” kodu döndürür; || operatörü sayesinde değişiklik varsa commit atılır, yoksa hiçbir şey yapılmaz.

💡 Cron sözdizimi: 0 6 * * * → dakika=0, saat=6, her gün, her ay, haftanın her günü. UTC kullandığını unutmayın; Türkiye saatiyle GMT+3, yani 09:00'da çalışır. Farklı bir saat için crontab.guru aracını kullanabilirsiniz.

6. Manuel Tetikleme 🖱️

Gihtub Actions Manuel Tetikleme

Cron job her sabah çalışır ama yeni bir makale yayınladığınızda beklemek istemeyebilirsiniz. workflow_dispatch tetikleyicisi sayesinde istediğiniz an çalıştırabilirsiniz:

  1. GitHub'da reponuza gidin
  2. Üstteki Actions sekmesine tıklayın
  3. Sol menüde 📝 Update Blog Articles workflow'una tıklayın
  4. Sağda beliren Run workflow butonuna tıklayın
  5. Açılan dropdown'da Run workflow butonuna tekrar tıklayın

Birkaç saniye içinde workflow başlar. Sol menüde sarı dönen bir ikon çıkar, tamamlanınca yeşil ✅ olur. README'nize baktığınızda yeni makale listesini göreceksiniz.

7. Demo 👀

Github Profile Readme Demo

Bu yazıda anlattığım sistemin çalışan örneğini kendi GitHub profilimde görebilirsiniz. Medium ve dev.to makaleleri her sabah otomatik olarak güncelleniyor.

👉 github.com/yasinatesim

Kaynak kodun tamamınafetch_articles.py ve update-articles.yml dahil aşağıdaki repodan ulaşabilirsiniz:

👉 github.com/yasinatesim/yasinatesim

📬 Geri bildirim

Makaleyi yazarken, yazım denetimi ve araştırma için “Claude Opus 4.6 Thinking” modelini kullandım. Resimleri üretmek için ise “Gemini 3.1 Flash Image Preview (Nano Banana 2)” modelini kullandım.

Yazı ile ilgili tavsiye, öneri, eleştirileri dikkate alıyorum. İletişime geçmek isterseniz bana websitemdeki sosyal medya adreslerimden veya Linkedin üzerinden ulaşabilirsiniz.

Sevgiyle kalın, Yasin 🤗

📚Makaleyi Yazarken Kullandığım Kaynaklar

Dokumanlar

Araçlar

İlham Veren README Örnekleri