{
  "id": "16SvkzB4jgrePTnC",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Environment Config Diff & Propagate for Android Builds",
  "tags": [],
  "nodes": [
    {
      "id": "71767832-90ad-4269-97ab-c23f32e2c317",
      "name": "Combine Env & Gradle",
      "type": "n8n-nodes-base.merge",
      "position": [
        -736,
        -2112
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "69c3ae90-b09c-4cc1-affd-d09078712e5a",
      "name": "Decode gradle.properties",
      "type": "n8n-nodes-base.code",
      "position": [
        800,
        -1920
      ],
      "parameters": {
        "jsCode": "const base64 = $json.content;\nconst decoded = Buffer.from(base64, 'base64').toString('utf8');\n\n// convert KEY=VALUE to object\nconst lines = decoded.split('\\n');\nconst env = {};\n\nfor (const line of lines) {\n  if (!line || line.startsWith('#')) continue;\n  const [key, ...rest] = line.split('=');\n  env[key] = rest.join('=');\n}\n\nreturn [{\n  raw: decoded,\n  parsed: env\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "6e18e5ea-bcab-4590-a177-6340b7d091a5",
      "name": "Receive GitHub Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1888,
        -2112
      ],
      "parameters": {
        "path": "env-config-diff",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2.1
    },
    {
      "id": "d939f1c6-ea57-4267-83df-f9169f618287",
      "name": "Check if .env.staging Changed",
      "type": "n8n-nodes-base.code",
      "position": [
        -1664,
        -2112
      ],
      "parameters": {
        "jsCode": "// Works for Postman AND real GitHub webhooks\nconst payload = $input.first().json.body ?? $input.first().json;\n\nconst commits = payload.commits || [];\nconst changedFiles = [];\n\nfor (const commit of commits) {\n  if (commit.added) changedFiles.push(...commit.added);\n  if (commit.modified) changedFiles.push(...commit.modified);\n  if (commit.removed) changedFiles.push(...commit.removed);\n}\n\nconst envFileChanged = changedFiles.includes('.env.staging');\n\nreturn [{\n  json: {\n    repository: payload.repository?.full_name,\n    branch: payload.ref,\n    envFileChanged,\n    changedFiles\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "9c6cdf35-2024-43b5-b90f-73161dc05a59",
      "name": "Proceed Only if ENV Changed",
      "type": "n8n-nodes-base.if",
      "position": [
        -1440,
        -2112
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "007202b7-7abf-4b2d-b940-c6382dc25f6d",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.envFileChanged }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "e3c6602c-e533-4cd4-841a-0c233433a8ed",
      "name": "Fetch .env.staging from Repo",
      "type": "n8n-nodes-base.github",
      "position": [
        -1216,
        -2208
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "list",
          "value": "tanvidg2025",
          "cachedResultUrl": "https://github.com/tanvidg2025",
          "cachedResultName": "tanvidg2025"
        },
        "filePath": ".env.staging",
        "resource": "file",
        "operation": "get",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "=android-config-sync-n8nDemo"
        },
        "asBinaryProperty": false,
        "additionalParameters": {
          "reference": "main"
        }
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "8668805d-adb4-4609-894a-429306cccc5b",
      "name": "Parse .env.staging into Key-Value",
      "type": "n8n-nodes-base.code",
      "position": [
        -992,
        -2208
      ],
      "parameters": {
        "jsCode": "// 1. Get Base64 content from GitHub node\nconst base64Content = $input.first().json.content;\n\n// 2. Decode Base64 to text\nconst decodedText = Buffer.from(base64Content, 'base64').toString('utf-8');\n\n// 3. Split lines and parse KEY=VALUE\nconst envLines = decodedText.split('\\n');\n\nconst envObject = {};\n\nfor (const line of envLines) {\n  const trimmed = line.trim();\n\n  // Ignore empty lines and comments\n  if (!trimmed || trimmed.startsWith('#')) continue;\n\n  const [key, ...valueParts] = trimmed.split('=');\n  envObject[key] = valueParts.join('=');\n}\n\nreturn [{\n  json: {\n    rawEnv: decodedText,\n    envVars: envObject\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "cafeceb7-63c6-4257-8cca-7596ac14e352",
      "name": "Fetch gradle.properties from Repo",
      "type": "n8n-nodes-base.github",
      "position": [
        -1216,
        -2016
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "list",
          "value": "tanvidg2025",
          "cachedResultUrl": "https://github.com/tanvidg2025",
          "cachedResultName": "tanvidg2025"
        },
        "filePath": "gradle.properties",
        "resource": "file",
        "operation": "get",
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "android-config-sync-n8nDemo",
          "cachedResultUrl": "https://github.com/tanvidg2025/android-config-sync-n8nDemo",
          "cachedResultName": "android-config-sync-n8nDemo"
        },
        "asBinaryProperty": false,
        "additionalParameters": {
          "reference": "main"
        }
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "b8df0df1-3cad-462b-ba86-c0db95a61ddf",
      "name": "Parse gradle.properties into Key-Value",
      "type": "n8n-nodes-base.code",
      "position": [
        -992,
        -2016
      ],
      "parameters": {
        "jsCode": "// 1. Get Base64 content\nconst base64Content = $input.first().json.content;\n\n// 2. Decode Base64\nconst decodedText = Buffer.from(base64Content, 'base64').toString('utf-8');\n\n// 3. Split lines\nconst lines = decodedText.split('\\n');\n\nconst gradleVars = {};\n\nfor (const line of lines) {\n  const trimmed = line.trim();\n\n  // Ignore comments and empty lines\n  if (!trimmed || trimmed.startsWith('#')) continue;\n\n  const [key, ...valueParts] = trimmed.split('=');\n  gradleVars[key] = valueParts.join('=');\n}\n\nreturn [{\n  json: {\n    rawGradle: decodedText,\n    gradleVars\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "25f75f8a-68cd-4c77-85cf-1bbcf90e2e9d",
      "name": "Compare ENV and Gradle Variables",
      "type": "n8n-nodes-base.code",
      "position": [
        -528,
        -2112
      ],
      "parameters": {
        "jsCode": "const inputArray = $input.all().map(item => item.json);\n\nconst envVars = inputArray[0]?.envVars || {};\nconst gradleVars = inputArray[1]?.gradleVars || {};\n\nconst changes = [];\nconst needsCacheInvalidation = [];\n\nfor (const key of Object.keys(envVars)) {\n  if (!gradleVars.hasOwnProperty(key)) {\n    changes.push({\n      key,\n      envValue: envVars[key],\n      gradleValue: null,\n      reason: 'missing_in_gradle'\n    });\n  } else if (envVars[key] !== gradleVars[key]) {\n    changes.push({\n      key,\n      envValue: envVars[key],\n      gradleValue: gradleVars[key],\n      reason: 'value_changed'\n    });\n  }\n\n  if (['API_KEY', 'BUILD_VERSION', 'ENVIRONMENT'].includes(key)) {\n    needsCacheInvalidation.push(key);\n  }\n}\n\nreturn [{\n  json: {\n    changes,\n    hasChanges: changes.length > 0,\n    needsCacheInvalidation,\n    envVars,\n    gradleVars\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "c6c4c5f5-e009-4dc6-a715-f0248939cbb9",
      "name": "Generate New Branch Name",
      "type": "n8n-nodes-base.code",
      "position": [
        -320,
        -2112
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst timestamp = new Date().toISOString().replace(/[:.]/g, '-');\nconst branchName = `config-sync/${timestamp}`;\n\nreturn [{\n  json: {\n    ...data,\n    branchName\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "05481330-eb64-4fd4-a7bd-b3582c1e5477",
      "name": "Get Latest SHA of main Branch",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -112,
        -2112
      ],
      "parameters": {
        "url": "{{Your_Github_URL_Here}}",
        "options": {},
        "sendHeaders": true,
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearar ghp_YOUR_GITHUB_TOKEN_HERE"
            },
            {
              "name": "Accept",
              "value": "application/vnd.github+json"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "nodeCredentialType": "githubApi"
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "1abcdfca-a4c4-4c17-a9bd-cacd7924daff",
      "name": "Prepare SHA for Branch Creation",
      "type": "n8n-nodes-base.set",
      "position": [
        96,
        -2112
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "8629de6b-d00b-4cea-b5aa-4b41145c5e17",
              "name": "=commitSHA",
              "type": "string",
              "value": "={{$json[\"object\"][\"sha\"]}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "00d3a128-9f51-45a1-a4b0-d4d517cc2fdd",
      "name": "Create New Git Branch",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        304,
        -2112
      ],
      "parameters": {
        "url": "{{Your_Github_URL_Here}}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"ref\": \"refs/heads/{{ $('Generate New Branch Name').item.json.branchName }}\",\n  \"sha\": \"{{$node[\"Prepare SHA for Branch Creation\"].json[\"commitSHA\"]}}\"\n}\n",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "githubApi"
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "0e1bd81a-eadf-4199-9453-16c319ca108d",
      "name": "Fetch .env.staging from New Branch",
      "type": "n8n-nodes-base.github",
      "position": [
        576,
        -2304
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "list",
          "value": "tanvidg2025",
          "cachedResultUrl": "https://github.com/tanvidg2025",
          "cachedResultName": "tanvidg2025"
        },
        "filePath": ".env.staging",
        "resource": "file",
        "operation": "get",
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "android-config-sync-n8nDemo",
          "cachedResultUrl": "https://github.com/tanvidg2025/android-config-sync-n8nDemo",
          "cachedResultName": "android-config-sync-n8nDemo"
        },
        "asBinaryProperty": false,
        "additionalParameters": {
          "reference": "={{ $json.ref }}"
        }
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "6462df63-65a2-499f-8210-1c313b36a157",
      "name": "Decode .env.staging",
      "type": "n8n-nodes-base.code",
      "position": [
        800,
        -2304
      ],
      "parameters": {
        "jsCode": "const base64 = $json.content;\nconst decoded = Buffer.from(base64, 'base64').toString('utf8');\n\n// convert KEY=VALUE to object\nconst lines = decoded.split('\\n');\nconst env = {};\n\nfor (const line of lines) {\n  if (!line || line.startsWith('#')) continue;\n  const [key, ...rest] = line.split('=');\n  env[key] = rest.join('=');\n}\n\nreturn [{\n  raw: decoded,\n  parsed: env\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "20a21eac-5e23-4bd1-bee3-a5f306959702",
      "name": "Fetch build.gradle File",
      "type": "n8n-nodes-base.github",
      "position": [
        576,
        -2112
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "list",
          "value": "tanvidg2025",
          "cachedResultUrl": "https://github.com/tanvidg2025",
          "cachedResultName": "tanvidg2025"
        },
        "filePath": "app/build.gradle",
        "resource": "file",
        "operation": "get",
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "android-config-sync-n8nDemo",
          "cachedResultUrl": "https://github.com/tanvidg2025/android-config-sync-n8nDemo",
          "cachedResultName": "android-config-sync-n8nDemo"
        },
        "asBinaryProperty": false,
        "additionalParameters": {}
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "f5ab4891-cb9a-461d-bcfc-3dd36953d02c",
      "name": "Fetch gradle.properties File",
      "type": "n8n-nodes-base.github",
      "position": [
        576,
        -1920
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "list",
          "value": "tanvidg2025",
          "cachedResultUrl": "https://github.com/tanvidg2025",
          "cachedResultName": "tanvidg2025"
        },
        "filePath": "gradle.properties",
        "resource": "file",
        "operation": "get",
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "android-config-sync-n8nDemo",
          "cachedResultUrl": "https://github.com/tanvidg2025/android-config-sync-n8nDemo",
          "cachedResultName": "android-config-sync-n8nDemo"
        },
        "asBinaryProperty": false,
        "additionalParameters": {}
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "f8d6ef7d-04ec-4a80-99fd-a273047d7574",
      "name": "Decode build.gradle",
      "type": "n8n-nodes-base.code",
      "position": [
        800,
        -2112
      ],
      "parameters": {
        "jsCode": "const base64 = $json.content;\nconst decoded = Buffer.from(base64, 'base64').toString('utf8');\n\n// convert KEY=VALUE to object\nconst lines = decoded.split('\\n');\nconst env = {};\n\nfor (const line of lines) {\n  if (!line || line.startsWith('#')) continue;\n  const [key, ...rest] = line.split('=');\n  env[key] = rest.join('=');\n}\n\nreturn [{\n  raw: decoded,\n  parsed: env\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "a23eccd8-e2c2-4fb2-b7ec-6a8e444044a3",
      "name": "Combine Decoded Files for Diff",
      "type": "n8n-nodes-base.merge",
      "position": [
        1008,
        -2128
      ],
      "parameters": {
        "numberInputs": 3
      },
      "typeVersion": 3.2
    },
    {
      "id": "6e10be61-22a7-422c-99f6-c93d03f07225",
      "name": "Identify Config Changes",
      "type": "n8n-nodes-base.code",
      "position": [
        1216,
        -2112
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\nif (items.length !== 3) {\n  throw new Error(`Expected 3 inputs, got ${items.length}`);\n}\n\n// Env file (source of truth)\nconst env = items[0].json.parsed;\n\n// build.gradle text (already decoded)\nconst buildGradleText = items[1].json.raw;\n\n// gradle.properties text (already decoded)\nconst gradlePropsText = items[2].json.raw;\n\nconst updates = {\n  buildGradle: {},\n  gradleProperties: {}\n};\n\nfor (const [key, value] of Object.entries(env)) {\n\n  // build.gradle \u2192 buildConfigField\n  if (buildGradleText.includes(`\"${key}\"`)) {\n    updates.buildGradle[key] = value;\n  }\n\n  // gradle.properties \u2192 KEY=value\n  if (gradlePropsText.includes(`${key}=`)) {\n    updates.gradleProperties[key] = value;\n  }\n}\n\nreturn [\n  {\n    json: {\n      updates,\n      hasChanges:\n        Object.keys(updates.buildGradle).length > 0 ||\n        Object.keys(updates.gradleProperties).length > 0\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "b1850639-ae21-44ad-ad94-67ca0ea20d7c",
      "name": "Apply ENV Changes to build.gradle",
      "type": "n8n-nodes-base.code",
      "position": [
        1472,
        -2208
      ],
      "parameters": {
        "jsCode": "const updates = $items(\"Identify Config Changes\")[0].json.updates.buildGradle;\nlet raw = $items(\"Decode build.gradle\")[0].json.raw;\n\nfor (const [key, value] of Object.entries(updates)) {\n  const regex = new RegExp(\n    `(buildConfigField\\\\s+\"String\",\\\\s+\"${key}\",\\\\s+\"\\\\\\\\\")(.*?)(\")`,\n    \"g\"\n  );\n  raw = raw.replace(regex, `$1${value}$3`);\n}\n\nreturn [{\n  json: {\n    path: \"app/build.gradle\",\n    content: Buffer.from(raw).toString(\"base64\"),\n    message: \"Sync env vars to build.gradle\"\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "8e0710a8-f595-4904-88d2-5edbf5893087",
      "name": "Apply ENV Changes to gradle.properties",
      "type": "n8n-nodes-base.code",
      "position": [
        1472,
        -2016
      ],
      "parameters": {
        "jsCode": "const updates = $items(\"Identify Config Changes\")[0].json.updates.gradleProperties;\nlet raw = $items(\"Decode gradle.properties\")[0].json.raw;\n\nfor (const [key, value] of Object.entries(updates)) {\n  const regex = new RegExp(`^${key}=.*$`, \"gm\");\n  if (raw.match(regex)) {\n    raw = raw.replace(regex, `${key}=${value}`);\n  } else {\n    raw += `\\n${key}=${value}`;\n  }\n}\n\nreturn [{\n  json: {\n    path: \"gradle.properties\",\n    content: Buffer.from(raw).toString(\"base64\"),\n    message: \"Sync env vars to gradle.properties\"\n  }\n}];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "b4daf1e6-d646-4e5e-a941-e2680216638f",
      "name": "Commit build.gradle Updates to Branch",
      "type": "n8n-nodes-base.github",
      "position": [
        1696,
        -2208
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "list",
          "value": "tanvidg2025",
          "cachedResultUrl": "https://github.com/tanvidg2025",
          "cachedResultName": "tanvidg2025"
        },
        "filePath": "={{ $json.path }}",
        "resource": "file",
        "operation": "edit",
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "android-config-sync-n8nDemo",
          "cachedResultUrl": "https://github.com/tanvidg2025/android-config-sync-n8nDemo",
          "cachedResultName": "android-config-sync-n8nDemo"
        },
        "fileContent": "={{ $json.content }}",
        "commitMessage": "={{ $json.message }}",
        "additionalParameters": {
          "branch": {
            "branch": "={{ $('Generate New Branch Name').first().json.branchName }}"
          }
        }
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "fbc4f688-af39-4d8e-816d-407b28a52913",
      "name": "Commit gradle.properties Updates to Branch",
      "type": "n8n-nodes-base.github",
      "position": [
        1696,
        -2016
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "list",
          "value": "tanvidg2025",
          "cachedResultUrl": "https://github.com/tanvidg2025",
          "cachedResultName": "tanvidg2025"
        },
        "filePath": "={{ $json.path }}",
        "resource": "file",
        "operation": "edit",
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "android-config-sync-n8nDemo",
          "cachedResultUrl": "https://github.com/tanvidg2025/android-config-sync-n8nDemo",
          "cachedResultName": "android-config-sync-n8nDemo"
        },
        "fileContent": "={{ $json.content }}",
        "commitMessage": "={{ $json.message }}",
        "additionalParameters": {
          "branch": {
            "branch": "={{ $('Generate New Branch Name').first().json.branchName }}"
          }
        }
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "a2e326b5-1f1b-41c3-a4d7-c2bfda307158",
      "name": "Prepare Pull Request Data",
      "type": "n8n-nodes-base.set",
      "position": [
        1952,
        -2112
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "14d22051-7cf7-4cc7-9c80-4a3a95e3ba3a",
              "name": "branchName",
              "type": "string",
              "value": "={{ $('Generate New Branch Name').first().json.branchName }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a60cba8b-7fe9-451c-aa5d-b5798093d24d",
      "name": "Create Pull Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2160,
        -2112
      ],
      "parameters": {
        "url": "{{Your_Github_URL_Here}}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"title\": \"Sync Android config files\",\n  \"body\": \"Auto-generated PR from n8n\",\n  \"head\": \"{{ $json.branchName }}\",\n  \"base\": \"main\"\n}\n",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "Accept",
              "value": "application/vnd.github+json"
            }
          ]
        },
        "nodeCredentialType": "githubApi"
      },
      "credentials": {
        "githubApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "ef65909b-64bd-4cde-ad28-f73d2d6fbdf6",
      "name": "Notify Team on Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        2368,
        -2112
      ],
      "parameters": {
        "text": ":rocket: A new pull request has been created!\n*Title:* Sync Android config files\n*Branch:* {{ $json.branchName }}\n*PR Link:* {{ $json.pullRequest.html_url }}\n",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C09S57E2JQ2",
          "cachedResultName": "n8n"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "8b662d1a-5f2e-4b8d-b939-bda32ad98a1c",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1968,
        -2208
      ],
      "parameters": {
        "color": 7,
        "height": 256,
        "content": "Listens for changes in the repository, like when someone updates files. This starts the workflow automatically."
      },
      "typeVersion": 1
    },
    {
      "id": "62225cd0-4919-429a-b9b3-8240d9ddbfbd",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1712,
        -2272
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 336,
        "content": "## Check if .env.staging Changed + Proceed Only if ENV Changed \nChecks whether the .env.staging file was modified in the recent commit. The workflow continues only if this file has changed."
      },
      "typeVersion": 1
    },
    {
      "id": "3b93d060-e5dd-4bbf-ac31-f3ca1bc5589e",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1280,
        -2336
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 496,
        "content": "## Fetch & Parse Files \nFetches the .env.staging and gradle.properties files from the repository and converts them into a simple key-value format so we can easily compare and use the values."
      },
      "typeVersion": 1
    },
    {
      "id": "27576e57-e18e-4293-8116-abaf3bda3949",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -768,
        -2240
      ],
      "parameters": {
        "color": 7,
        "width": 1216,
        "height": 352,
        "content": "## Combine & Prepare Branch\nCompares the values in .env.staging and gradle.properties to see what needs updating. Then, creates a new branch from the main branch to apply these updates safely."
      },
      "typeVersion": 1
    },
    {
      "id": "af5d8308-0f67-4799-a08f-24be27d0f3bd",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        464,
        -2464
      ],
      "parameters": {
        "color": 7,
        "width": 912,
        "height": 720,
        "content": "## Fetch & Decode Files for Diff\nFetches the latest versions of config files from the new branch, decodes them into readable text and prepares a comparison to see exactly which values need to be updated."
      },
      "typeVersion": 1
    },
    {
      "id": "6ac689dd-91c3-48f3-99c7-0410b0ff1552",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1392,
        -2336
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 496,
        "content": "## Update Files\n\nUpdates the build.gradle and gradle.properties files with the new values from .env.staging and commits these changes to the new branch.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c6c32328-88fd-4cfa-ab81-31e18a7434dc",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1904,
        -2256
      ],
      "parameters": {
        "color": 7,
        "width": 656,
        "height": 352,
        "content": "## Create Pull Request & Notify\n\nPrepares and creates a pull request for the updated files and sends a message to the team on Slack to let them know a new PR is ready for review.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "8d8186d8-9195-41f9-9719-b00e6c8fafdc",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2752,
        -3072
      ],
      "parameters": {
        "width": 416,
        "height": 672,
        "content": "## How it works\n\nThis workflow starts automatically when a change is pushed to GitHub. It first checks whether the .env.staging file was modified and if not, the workflow stops immediately. When .env.staging has changed, the workflow reads the environment values and compares them with the existing values in build.gradle and gradle.properties. If differences are found, it creates a new branch from the main branch, applies only the required updates to the Android configuration files and commits those changes to the new branch. After committing, it creates a pull request so the changes can be reviewed safely before merging. Finally, a Slack notification is sent to inform the team that a configuration update pull request is ready.\n\n\n## Setup steps\n\n**1.** Import this workflow into n8n.\n\n**2.** Connect your GitHub credentials.\n\n**3.** Connect your Slack credentials and select a channel.\n\n**4.** Make sure .env.staging, build.gradle and gradle.properties exist in the repo.\n\n**5.** Activate the workflow.\n\n**6.** Push a change to .env.staging to test."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c09ae9e6-8fe1-4fa1-9da4-c0608f1a0852",
  "connections": {
    "Create Pull Request": {
      "main": [
        [
          {
            "node": "Notify Team on Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Decode .env.staging": {
      "main": [
        [
          {
            "node": "Combine Decoded Files for Diff",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Decode build.gradle": {
      "main": [
        [
          {
            "node": "Combine Decoded Files for Diff",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Combine Env & Gradle": {
      "main": [
        [
          {
            "node": "Compare ENV and Gradle Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create New Git Branch": {
      "main": [
        [
          {
            "node": "Fetch .env.staging from New Branch",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch build.gradle File",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch gradle.properties File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive GitHub Webhook": {
      "main": [
        [
          {
            "node": "Check if .env.staging Changed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch build.gradle File": {
      "main": [
        [
          {
            "node": "Decode build.gradle",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Identify Config Changes": {
      "main": [
        [
          {
            "node": "Apply ENV Changes to build.gradle",
            "type": "main",
            "index": 0
          },
          {
            "node": "Apply ENV Changes to gradle.properties",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Decode gradle.properties": {
      "main": [
        [
          {
            "node": "Combine Decoded Files for Diff",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Generate New Branch Name": {
      "main": [
        [
          {
            "node": "Get Latest SHA of main Branch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Pull Request Data": {
      "main": [
        [
          {
            "node": "Create Pull Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Proceed Only if ENV Changed": {
      "main": [
        [
          {
            "node": "Fetch .env.staging from Repo",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch gradle.properties from Repo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch .env.staging from Repo": {
      "main": [
        [
          {
            "node": "Parse .env.staging into Key-Value",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch gradle.properties File": {
      "main": [
        [
          {
            "node": "Decode gradle.properties",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if .env.staging Changed": {
      "main": [
        [
          {
            "node": "Proceed Only if ENV Changed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Latest SHA of main Branch": {
      "main": [
        [
          {
            "node": "Prepare SHA for Branch Creation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine Decoded Files for Diff": {
      "main": [
        [
          {
            "node": "Identify Config Changes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare SHA for Branch Creation": {
      "main": [
        [
          {
            "node": "Create New Git Branch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compare ENV and Gradle Variables": {
      "main": [
        [
          {
            "node": "Generate New Branch Name",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apply ENV Changes to build.gradle": {
      "main": [
        [
          {
            "node": "Commit build.gradle Updates to Branch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch gradle.properties from Repo": {
      "main": [
        [
          {
            "node": "Parse gradle.properties into Key-Value",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse .env.staging into Key-Value": {
      "main": [
        [
          {
            "node": "Combine Env & Gradle",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch .env.staging from New Branch": {
      "main": [
        [
          {
            "node": "Decode .env.staging",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Commit build.gradle Updates to Branch": {
      "main": [
        [
          {
            "node": "Prepare Pull Request Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apply ENV Changes to gradle.properties": {
      "main": [
        [
          {
            "node": "Commit gradle.properties Updates to Branch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse gradle.properties into Key-Value": {
      "main": [
        [
          {
            "node": "Combine Env & Gradle",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Commit gradle.properties Updates to Branch": {
      "main": [
        [
          {
            "node": "Prepare Pull Request Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}