🔧 AI Nachrichten Security Weekly - A CRA Resource: AI Doesn't Actually Think(18.09.2026 um 00:09 Uhr)
🔧 AI Nachrichten Security Weekly - A CRA Resource: AI Doesn't Actually Think(18.09.2026 um 00:09 Uhr)
🔧 Programmierung 🕛 vor 5 Monaten 6 Min Lesezeit
0

How I Automated Weekly Twitter/X Posts With GitHub Actions

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Every Monday at 10 AM Eastern, is a static site with 113 code patterns showing the old way vs. the modern way to write Java. Each pattern has a title, summary, old/modern approach labels, JDK version, and a link to its detail page.



I wanted to promote each pattern on Twitter — one per week, in random order, cycling forever. The requirements:





  • Fully automated — no manual tweeting


  • Pre-drafted tweets — reviewable and editable before they go live


  • Resumable — survives failures, picks up where it left off


  • Auditable — git history shows what was posted and when


  • Zero infrastructure — no servers, no databases, no paid services






The Architecture



The system has three components:




CODE
content/*.yaml → [Queue Generator] → social/queue.txt
→ social/tweets.yaml
→ social/state.yaml

social/* → [Post Script] → Twitter API v2 → updated state

GitHub Actions cron → runs Post Script every Monday






Everything lives in the repository. State is tracked via committed files, not external databases.






Component 1: The Queue & Tweet Generator



File: html-generators/generatesocialqueue.java



A JBang script that scans all content YAML files, shuffles them randomly, and produces three files:





  • social/queue.txt — the posting order, one category/slug per line


  • social/tweets.yaml — pre-drafted tweet text for each pattern


  • social/state.yaml — a pointer tracking where we are in the queue



The tweet template looks like this:




CODE
☕ {title}

{summary}

{oldApproach} → {modernApproach} (JDK {jdkVersion}+)

🔗 https://javaevolved.github.io/{category}/{slug}.html

#Java #JavaEvolved






The generator also validates that every tweet fits within Twitter's 280-character limit. If a summary is too long, it's automatically truncated with an ellipsis. Of the 113 patterns, 12 needed truncation.






Handling New Patterns



When you re-run the generator after adding new content files, it detects new patterns and appends them to the end of the existing queue — preserving the current order and any manual tweet edits. Deleted or renamed patterns are automatically pruned.



Use --reshuffle to force a full reshuffle when the cycle is exhausted.






Component 2: The Post Script



File: html-generators/socialpost.java



Another JBang script that:




  1. Reads the current index from social/state.yaml

  2. Looks up the next pattern key in social/queue.txt

  3. Retrieves the pre-drafted tweet text from social/tweets.yaml

  4. Posts to the Twitter API v2 using OAuth 1.0a

  5. Updates the state file only after confirmed API success






OAuth 1.0a in Java



I initially planned to use a shell script with curl and openssl for OAuth signing. That turned out to be a bad idea — percent-encoding, signature base strings, and nonce generation are error-prone in Bash.



Instead, the post script uses Java's built-in java.net.http.HttpClient and javax.crypto.Mac for HMAC-SHA1 signing. Here's the core of the OAuth signature:




CODE
// Build signature base string
var paramString = oauthParams.entrySet().stream()
.map(e -> percentEncode(e.getKey()) + "=" + percentEncode(e.getValue()))
.collect(Collectors.joining("&"));

var baseString = method + "&" + percentEncode(url) + "&" + percentEncode(paramString);
var signingKey = percentEncode(consumerSecret) + "&" + percentEncode(tokenSecret);

// HMAC-SHA1
var mac = javax.crypto.Mac.getInstance("HmacSHA1");
mac.init(new javax.crypto.spec.SecretKeySpec(
signingKey.getBytes(UTF_8), "HmacSHA1"));
var signature = Base64.getEncoder().encodeToString(
mac.doFinal(baseString.getBytes(UTF_8)));






The script also supports --dry-run to preview the next tweet without posting:




CODE
$ jbang html-generators/socialpost.java --dry-run

Queue has 113 entries, current index: 1
Pattern: language/guarded-patterns
Tweet (200 chars):
---
☕ Guarded patterns with when

Add conditions to pattern cases using when guards.

Nested if → when Clause (JDK 21+)

🔗 https://javaevolved.github.io/language/guarded-patterns.html

#Java #JavaEvolved
---
DRY RUN — not posting.









Component 3: The GitHub Actions Workflow



File: .github/workflows/social-post.yml




CODE
name: Weekly Social Post

on:
schedule:
- cron: '0 14 * * 1' # Every Monday at 14:00 UTC (10 AM ET)
workflow_dispatch: # Manual trigger

concurrency:
group: social-post
cancel-in-progress: false

jobs:
post:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '25'
- uses: jbangdev/setup-jbang@main

- name: Post to Twitter
env:
TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_APP_CONSUMER_KEY }}
# ... other secrets
run: jbang html-generators/socialpost.java

- name: Commit updated state
run: |
git add social/state.yaml
git commit -m "chore: update social post state [skip ci]"
git pull --rebase
git push






A few details worth noting:





  • concurrency group prevents double-posts if a manual dispatch overlaps with the cron


  • [skip ci] in the commit message prevents the state update from triggering other workflows


  • Social files live in social/, not content/ — the deploy workflow watches content/**, so keeping state separate avoids unnecessary site rebuilds


  • git pull --rebase before push handles the rare case where another commit lands between checkout and push






The Economics



Twitter's API pricing means each tweet costs about $0.01. With 113 patterns posted weekly:




  • ~$0.52/year


  • ~2.2 years of unique content per cycle before reshuffling



That's essentially free for a perpetual social media presence.






Built in a Single Copilot CLI Session



This entire feature — the queue generator, the post script, the GitHub Actions workflow, the tweet drafts, the documentation updates — was built in a single interactive session with






What I'd Do Differently





  • Add Bluesky support — the AT Protocol API is simpler than Twitter's OAuth 1.0a. The architecture already supports it; just add a second API call in the post script.


  • Content hash tracking — if a pattern's title or summary changes, the pre-drafted tweet goes stale. A hash per entry would flag which drafts need regeneration.






Try It Yourself



The entire implementation is open source at

  • Content in YAML with title, summary, oldApproach, modernApproach, jdkVersion, category, and slug fields



  • Generate the queue, review the drafts, push, and let GitHub Actions handle the rest.






    Follow @javaevolved for a new modern Java pattern every Monday.

    Vollständiger Original-Artikel
    Den kompletten Beitrag mit allen Details direkt auf dev.to lesen.
    ↗ Original-Artikel auf dev.to lesen
    Wie bewertest du diesen Beitrag?
    1 Klick Feedback
    Teilen mit Netzwerk & Team:

    Community-Analysen & Experten-Meinungen 0

    Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
    Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
    Community Pulse: Relevanz-Einschätzung
    1 Klick Experten-Votum
    🔴 Akute Relevanz 0%
    🟡 In Evaluierung 0%
    🟢 Keine Auswirkung 0%
    Spannende Innovation 0%
    Verwandte Story-Cluster & Quellen (Vektor-KI)
    Port 8095 Engine
    1 Quelle
    Microsoft Office Ohne Abonnement? Jetzt kostet es ein paar Hundert - Jablíčkář
    1 Quelle
    Windows Defender: Falsche Warnung täuscht Sicherheitslücke vor - ad-hoc-news.de
    1 Quelle
    DFN-CERT-2026-4930 FFmpeg: Mehrere Schwachstellen ermöglichen u. a. das Ausführen ...
    Ähnliche Beiträge
    🔍 Verwandte News

    Auch interessante Nachrichten How I Automated Weekly Twitter/X Posts With GitHub Actions

    Thematisch verwandte Begriffe: Automated, Weekly, TwitterX, Posts · 6 Treffer

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...

    Laden...

    Beiträge werden geladen ...

    Laden...

    Videos werden geladen ...