Generar publicaciones para Twitter y LinkedIn desde push de GitHub

Avanzado

Este es unMultimodal AIflujo de automatización del dominio deautomatización que contiene 18 nodos.Utiliza principalmente nodos como If, Merge, Github, Twitter, Webhook. Usar GPT-4o y OAuth para generar automáticamente publicaciones de redes sociales a partir de actualizaciones de GitHub README/CHANGELOG

Requisitos previos
  • Personal Access Token de GitHub
  • Credenciales de API de Twitter
  • Punto final de HTTP Webhook (n8n generará automáticamente)
  • Credenciales de API de LinkedIn
  • Clave de API de OpenAI

Categoría

Vista previa del flujo de trabajo
Visualización de las conexiones entre nodos, con soporte para zoom y panorámica
Exportar flujo de trabajo
Copie la siguiente configuración JSON en n8n para importar y usar este flujo de trabajo
{
  "id": "zMl1xguA65ATPxMh",
  "meta": {
    "instanceId": "6bad1eba185697a960de5bc9203d6bff2fd56440a0b5303c382e0b1537a2a568",
    "templateCredsSetupCompleted": true
  },
  "name": "Generate social posts from GitHub pushes to Twitter and LinkedIn",
  "tags": [],
  "nodes": [
    {
      "id": "29f468dd-8822-4de7-9bf7-0205e8b51b12",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -640,
        -144
      ],
      "webhookId": "70b80513-b93c-4749-9a06-e78d4f1f2d23",
      "parameters": {
        "path": "70b80513-b93c-4749-9a06-e78d4f1f2d23",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2
    },
    {
      "id": "a991ef0a-48ef-4ccf-98c6-587edddafa96",
      "name": "Combinar",
      "type": "n8n-nodes-base.merge",
      "position": [
        400,
        -80
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "a19b66f5-0927-4c59-8343-f2cea29feb5e",
      "name": "Obtener README",
      "type": "n8n-nodes-base.github",
      "position": [
        64,
        -208
      ],
      "webhookId": "eab25bcf-6820-4ee6-ab43-7ec9f5a9e413",
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "jorge210488"
        },
        "filePath": "README.md",
        "resource": "file",
        "operation": "get",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.body.repository.name }}"
        },
        "additionalParameters": {}
      },
      "credentials": {
        "githubApi": {
          "id": "O2s7MSmQAwSFAbN5",
          "name": "GitHub account"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "b3ae8e15-dd37-4207-a78c-4b18b72c9cb8",
      "name": "Obtener CHANGELOG",
      "type": "n8n-nodes-base.github",
      "position": [
        64,
        32
      ],
      "webhookId": "eab25bcf-6820-4ee6-ab43-7ec9f5a9e413",
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "jorge210488"
        },
        "filePath": "CHANGELOG.md",
        "resource": "file",
        "operation": "get",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.body.repository.name }}"
        },
        "additionalParameters": {}
      },
      "credentials": {
        "githubApi": {
          "id": "O2s7MSmQAwSFAbN5",
          "name": "GitHub account"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "9229a69b-fe35-4a25-a8d8-bc3e1f6d8894",
      "name": "Si",
      "type": "n8n-nodes-base.if",
      "position": [
        -448,
        -144
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "fb7ff717-d8a0-44ed-9053-1e88d50f88de",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{\n  ($json.body.commits ?? []).some(c =>\n    [ ...(c.added ?? []), ...(c.modified ?? []), ...(c.removed ?? []) ]\n      .some(f => String(f).toLowerCase().includes('changelog'))\n  )\n}}",
              "rightValue": "="
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4e9ebbbd-9c37-4dbe-a9b6-dc0f72a85877",
      "name": "Sin operación, no hacer nada",
      "type": "n8n-nodes-base.noOp",
      "position": [
        -256,
        48
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "e35435d4-f3f8-44f1-ac78-21efda7076ac",
      "name": "Agregar",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        560,
        -80
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "82c95a95-4a00-405d-a826-9c387a3f76be",
      "name": "Cadena Básica LLM",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        832,
        -80
      ],
      "parameters": {
        "text": "=README: {{ $json.data[0].data }}\nCHANGELOG: {{ $json.data[1].data }}",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "=# Role\n\nYou are a precise content generator for social media.\nYour input will be a JSON object with two string fields:\n\n* `README`: full project README in Markdown.\n* `CHANGELOG`: full changelog in Markdown.\n\n## Your task\n\nProduce **one JSON object** with exactly two keys:\n\n```json\n{\n  \"twitter\": \"<tweet in English, <=280 chars including the GitHub link>\",\n  \"linkedin\": \"<LinkedIn post in English, long-form>\"\n}\n```\n\nNo extra keys, no surrounding text, no Markdown fences.\n\n## Parsing rules (do not hallucinate)\n\n1. **Repository URL (required in both posts):**\n\n   * Extract the **first** URL that matches a GitHub repo pattern from `CHANGELOG` using a regex like:\n     `https?://github\\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+`\n   * If not found in `CHANGELOG`, search `README` with the same regex.\n   * If still not found, **do not fabricate** a URL; instead, use the literal placeholder `https://github.com/REPO_MISSING`. (Keep generating the posts.)\n\n2. **Project name:**\n\n   * Prefer the first H1 (`# Title`) in `README`. If not present, infer a concise name from the first heading found. If impossible, use a short neutral name like “This project”.\n\n3. **First release or update determination:**\n\n   * From `CHANGELOG`, detect if this is the **first or only version** (e.g., version numbers like `v1.0.0`, \"Initial release\", or only one version section present).\n   * If first/only version → the post should clearly state it's a **new project/app/development** (e.g., “New project”, “Launching a new application”).\n   * If not first version → the post should state it’s an **update or improvement** (e.g., “Updating the project X”, “Improving the application X”).\n\n4. **Description & features:**\n\n   * Derive a clear, one-sentence value proposition from `README`’s Description/Overview.\n   * Collect 4–7 key capabilities/benefits (bullets for LinkedIn).\n\n5. **Tech stack:**\n\n   * From `README`, extract notable technologies (backend, frontend, infra/services).\n   * Examples to detect if present: Django, DRF, Celery, Redis, Channels/WebSockets, Next.js, React, TypeScript, Tailwind CSS, Zustand, Framer Motion, Stripe, OpenAI, OAuth/Google, SMTP/Email, Docker, Docker Compose.\n   * For **Twitter**, mention only the **3–4 most central** technologies.\n   * For **LinkedIn**, you may group by Backend / Frontend / Infra.\n\n## LinkedIn post (English, long-form)\n\n* Tone: professional, enthusiastic, concise sentences; **no emojis**.\n* Structure (use short paragraphs and bullet points):\n\n  * Hook:\n\n    * If first release → start with “New project: …” or similar phrasing.\n    * If update → start with “Updating the project \\[name]: …” or similar phrasing.\n  * What it does: 1 short paragraph.\n  * Key features/benefits: 4–7 bullets.\n  * Tech stack (grouped): bullets for Backend, Frontend, Infra/Services.\n  * Motivational developer line (one sentence, non-cheesy).\n  * Call to action with the **repo link** (exactly once).\n* Hashtags: **8–12** relevant tags, all lowercase, no spaces (use hyphens only if part of the tech brand). Prioritize technologies and domain, e.g.:\n  `#python #django #nextjs #typescript #tailwindcss #stripe #openai #celery #redis #websockets #ai #saas #startups #webdevelopment`\n  (Pick only those truly present; don’t invent.)\n\n## Twitter post (English, max 280 chars including link)\n\n* Format:\n\n  * If first release → short sentence like “New project: …” or similar.\n  * If update → short sentence like “Updating project \\[name]: …” or similar.\n* Describe what the app does + **repo link** (once).\n* Mention **3–4** main technologies inline (e.g., Django, Next.js, Stripe, OpenAI).\n* **2–3 hashtags max**, chosen from the most relevant.\n* **No emojis.**\n* Length enforcement: if >280 chars, iteratively shorten by (in order): remove adjectives, compress wording, then drop one hashtag at a time until ≤280. Never drop the repo link.\n\n## Output formatting\n\n* Return a **single JSON object** with keys `\"twitter\"` and `\"linkedin\"`.\n* Escape quotes properly.\n* Do **not** add explanations, markdown, or extra whitespace before/after the JSON.\n* Do not include any links other than the repo link.\n\n## Safety & accuracy\n\n* Never fabricate tech or features not present in the inputs.\n* If some sections are missing in inputs, omit that detail gracefully.\n* Keep everything in **English** except hashtags which are typically lowercase English tokens.\n* Do not output dates/releases unless explicitly present.\n* Maintain a positive, credible tone.\n"
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "927afa09-65bf-4c62-955c-42a3bb098f28",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        832,
        80
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "9RjbvMHnwZg2LraO",
          "name": "OpenAi ROD"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "43f2f142-8319-445f-80a9-61c56ae6ddad",
      "name": "Analizador de Salida Estructurada",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1008,
        80
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"twitter\": \"tweet in English, <=280 chars including the GitHub link\",\n  \"linkedin\": \"LinkedIn post in English, long-form\"\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "c2454817-d07d-45e0-8c5f-03a68c619eb8",
      "name": "Publicar tweet",
      "type": "n8n-nodes-base.twitter",
      "position": [
        1248,
        48
      ],
      "parameters": {
        "text": "={{ $json.output.twitter }}",
        "additionalFields": {}
      },
      "credentials": {
        "twitterOAuth2Api": {
          "id": "VF7lxb5r1ouC0O22",
          "name": "X account"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "944f1559-f79e-4034-b70f-0246c8b40a5f",
      "name": "LinkedIn",
      "type": "n8n-nodes-base.linkedIn",
      "position": [
        1248,
        -160
      ],
      "parameters": {
        "text": "={{ $json.output.linkedin }}",
        "person": "nUdV-_cHkk",
        "additionalFields": {}
      },
      "credentials": {
        "linkedInOAuth2Api": {
          "id": "Slo13uTVYAdaV30t",
          "name": "LinkedIn account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d64cf42e-40b0-4db8-9748-774751840a14",
      "name": "Nota adhesiva",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -720,
        -720
      ],
      "parameters": {
        "width": 660,
        "height": 900,
        "content": "# GitHub Push → README & CHANGELOG check\n\n## 1) Webhook (receive push from GitHub)\n* **Node:** Webhook (POST)\n* **GitHub setup:** Repository → *Settings → Webhooks → Add webhook*\n  * **Payload URL:** `https://<your-n8n-domain>/webhook/github/push`\n  * **Content type:** `application/json`\n  * **Event:** *Just the push event*\n  * **Secret:** optional\n  * **Branches:** choose specific branches or send all\n## 2) IF (filter)\n* **Node:** IF\n* **Checks:** push contains `README` and `CHANGELOG` in *added* or *modified* files\n* **True:** continue\n* **False:** do nothing (stop)\n"
      },
      "typeVersion": 1
    },
    {
      "id": "b08176e7-283f-4ed3-8c54-c90daeb05d59",
      "name": "Nota adhesiva1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        48,
        -720
      ],
      "parameters": {
        "color": 4,
        "width": 640,
        "height": 920,
        "content": "# GitHub → Extract → Merge/Aggregate\n\n## 1) GitHub (Get Repository File)\n* **Credentials:** GitHub OAuth2 or PAT with read access.\n* **Owner/Repo/Branch:** from webhook payload (`body.repository`, branch from `body.ref`).\n* **File Path:** `README.md` and `CHANGELOG.md` (use two GitHub nodes).\n* **Output:** binary files.\n## 2) Extract from File (text)\n* **Operation:** `text`.\n* **Input:** binary from each GitHub node.\n* **Output:** plain text for README and CHANGELOG.\n## 3) Merge & Aggregate\n* **Merge:** *Wait for Both* (combine README + CHANGELOG into one item).\n* **Aggregate:** `aggregateAllItemData` (single item with `documents` list holding both contents).\n"
      },
      "typeVersion": 1
    },
    {
      "id": "90e42f76-4ca3-4e6d-902c-2b4f1e29c0a4",
      "name": "Nota adhesiva2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        752,
        -720
      ],
      "parameters": {
        "width": 720,
        "height": 920,
        "content": "# LLM → Post to Twitter & LinkedIn\n\n## 1) LLM (OpenAI → JSON)\n* Nodes: OpenAI Chat Model → Basic LLM Chain (+ Structured Output Parser)\n* Input: aggregated README + CHANGELOG\n* Output: JSON with `\"twitter\"` and `\"linkedin\"`\n## 2) Publish\n* **Twitter node**\n  * Auth: credentials\n* **LinkedIn node (Person)**\n  * Auth: credentials\n  * Required scope: `w_member_social`, `openid`\n"
      },
      "typeVersion": 1
    },
    {
      "id": "3f31d48b-c0cc-4140-9bd8-02f4267f7f65",
      "name": "Nota adhesiva3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1520,
        -720
      ],
      "parameters": {
        "color": 5,
        "width": 780,
        "height": 900,
        "content": "# Generate social posts from GitHub pushes to Twitter and LinkedIn\nOn each GitHub *push*, this workflow checks if the commit set includes **README.md** and **CHANGELOG.md**, fetches both files, lets an **LLM** generate a Twitter and LinkedIn post, then publishes to **Twitter** and **LinkedIn (Person)**.\n## Apps & Nodes\n* **Trigger:** Webhook\n* **Logic:** IF, Merge, Aggregate\n* **GitHub:** Get Repository File (×2)\n* **Files:** Extract from File (text) (×2)\n* **AI:** OpenAI Chat Model → LLM Chain (+ Structured Output Parser)\n* **Publish:** Twitter, LinkedIn (Person)\n## Prerequisites\n* **GitHub:** OAuth2 or PAT with repo read.\n* **OpenAI:** API key.\n* **Twitter:** OAuth2 app with *Read and Write*; scopes `tweet.read tweet.write users.read offline.access`.\n* **LinkedIn (Person):** OAuth2 credentials; **required scope:** `w_member_social`, `openid`.\n## Setup\n1. **GitHub Webhook:** Repo → *Settings → Webhooks*\n\n   * Payload URL: `https://<your-n8n-domain>/webhook/github/push`\n   * Content type: `application/json` • Event: *Push* • Secret (optional) • Branches as needed.\n2. **Credentials:** Connect GitHub, OpenAI, Twitter, and LinkedIn (Person).\n## How it Works\n1. **Webhook** receives GitHub push payload.\n2. **IF** checks that `README` and `CHANGELOG` appear in *added/modified*.\n3. **GitHub (Get Repository File)** pulls `README.md` and `CHANGELOG.md`.\n4. **Extract from File (text)** converts both binaries to text.\n5. **Merge & Aggregate** combines into one item with both contents.\n6. **LLM (OpenAI + Parser)** returns a JSON with `twitter` and `linkedin`.\n7. **Twitter** posts the tweet.\n8. **LinkedIn (Person)** posts the LinkedIn text.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "95134ca6-76d8-49a2-ae2c-6f1d7121c9a6",
      "name": "Extraer de Archivo README",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        224,
        -208
      ],
      "parameters": {
        "options": {},
        "operation": "text"
      },
      "typeVersion": 1
    },
    {
      "id": "a61fd00a-34f2-4e8b-bdf5-7e9c686f58ed",
      "name": "Extraer de Archivo CHANGELOG",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        224,
        32
      ],
      "parameters": {
        "options": {},
        "operation": "text"
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "78f3c247-4dc6-474b-8a51-3a55a072dd92",
  "connections": {
    "9229a69b-fe35-4a25-a8d8-bc3e1f6d8894": {
      "main": [
        [
          {
            "node": "b3ae8e15-dd37-4207-a78c-4b18b72c9cb8",
            "type": "main",
            "index": 0
          },
          {
            "node": "a19b66f5-0927-4c59-8343-f2cea29feb5e",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "4e9ebbbd-9c37-4dbe-a9b6-dc0f72a85877",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a991ef0a-48ef-4ccf-98c6-587edddafa96": {
      "main": [
        [
          {
            "node": "e35435d4-f3f8-44f1-ac78-21efda7076ac",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "29f468dd-8822-4de7-9bf7-0205e8b51b12": {
      "main": [
        [
          {
            "node": "9229a69b-fe35-4a25-a8d8-bc3e1f6d8894",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "e35435d4-f3f8-44f1-ac78-21efda7076ac": {
      "main": [
        [
          {
            "node": "82c95a95-4a00-405d-a826-9c387a3f76be",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a19b66f5-0927-4c59-8343-f2cea29feb5e": {
      "main": [
        [
          {
            "node": "95134ca6-76d8-49a2-ae2c-6f1d7121c9a6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b3ae8e15-dd37-4207-a78c-4b18b72c9cb8": {
      "main": [
        [
          {
            "node": "a61fd00a-34f2-4e8b-bdf5-7e9c686f58ed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "82c95a95-4a00-405d-a826-9c387a3f76be": {
      "main": [
        [
          {
            "node": "c2454817-d07d-45e0-8c5f-03a68c619eb8",
            "type": "main",
            "index": 0
          },
          {
            "node": "944f1559-f79e-4034-b70f-0246c8b40a5f",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "927afa09-65bf-4c62-955c-42a3bb098f28": {
      "ai_languageModel": [
        [
          {
            "node": "82c95a95-4a00-405d-a826-9c387a3f76be",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "95134ca6-76d8-49a2-ae2c-6f1d7121c9a6": {
      "main": [
        [
          {
            "node": "a991ef0a-48ef-4ccf-98c6-587edddafa96",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "43f2f142-8319-445f-80a9-61c56ae6ddad": {
      "ai_outputParser": [
        [
          {
            "node": "82c95a95-4a00-405d-a826-9c387a3f76be",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "a61fd00a-34f2-4e8b-bdf5-7e9c686f58ed": {
      "main": [
        [
          {
            "node": "a991ef0a-48ef-4ccf-98c6-587edddafa96",
            "type": "main",
            "index": 1
          }
        ]
      ]
    }
  }
}
Preguntas frecuentes

¿Cómo usar este flujo de trabajo?

Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.

¿En qué escenarios es adecuado este flujo de trabajo?

Avanzado - IA Multimodal

¿Es de pago?

Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.

Información del flujo de trabajo
Nivel de dificultad
Avanzado
Número de nodos18
Categoría1
Tipos de nodos13
Descripción de la dificultad

Adecuado para usuarios avanzados, flujos de trabajo complejos con 16+ nodos

Autor
Jorge Martínez

Jorge Martínez

@jorgemartinezjam

AI Engineer & Full Stack Developer skilled in designing intelligent agents, workflow automation, and NLP solutions. Experienced with LLMs, Relevance AI, make, zapier, and n8n. Proficient in integrating AI and chatbots into web apps, optimizing processes, and leveraging automation for real-time productivity. Strong background in backend and frontend development, REST APIs, and database management.

Enlaces externos
Ver en n8n.io

Compartir este flujo de trabajo

Categorías

Categorías: 34