Android機能フラグディレクトリとLaunchDarklyの比較により無効フラグのクリーンアップ
中級
これはDevOps, Multimodal AI分野の自動化ワークフローで、11個のノードを含みます。主にIf, Code, Jira, Slack, Gitlabなどのノードを使用。 GitLab、LaunchDarkly、Jira、Slackを使って使用されないAndroid機能フラグを検出する
前提条件
- •Slack Bot Token または Webhook URL
- •GitLab Personal Access Token
- •ターゲットAPIの認証情報が必要な場合あり
- •Google Sheets API認証情報
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
"id": "Ozg0c8uxCru2a79p",
"meta": {
"instanceId": "14e4c77104722ab186539dfea5182e419aecc83d85963fe13f6de862c875ebfa"
},
"name": "Catalog Android (Kotlin/Java) feature flags and sweep dead flags vs LaunchDarkly (weekly) → Sheets + Jira + PR + Slack",
"tags": [],
"nodes": [
{
"id": "edcaa1e6-4fd2-4b06-93b5-b9219bbba407",
"name": "未使用フラグの確認",
"type": "n8n-nodes-base.if",
"position": [
40,
1680
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.deadFlag !== undefined}}",
"operation": "notEqual"
}
]
}
},
"typeVersion": 1
},
{
"id": "e603fbcb-275a-4356-acbf-d70a219f975c",
"name": "スケジュールトリガー",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-420,
1360
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtHour": 10
}
]
}
},
"typeVersion": 1.2
},
{
"id": "70dfcf7f-3d82-44d6-9ea2-ef550b5496f4",
"name": "GitLab",
"type": "n8n-nodes-base.gitlab",
"position": [
-200,
1360
],
"parameters": {
"owner": "",
"resource": "",
"operation": "",
"repository": "",
"authentication": ""
},
"credentials": {
"gitlabOAuth2Api": {
"id": "",
"name": ""
}
},
"typeVersion": 1
},
{
"id": "13799fe3-a8d0-4dc2-924f-a5c53c17dea5",
"name": "Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
-180,
1680
],
"parameters": {
"sheetName": {
"__rl": true,
"mode": "list",
"value": ""
},
"documentId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "",
"name": ""
}
},
"typeVersion": 4.6
},
{
"id": "958b3c35-f1ea-4ef4-8c7c-3a69869e4eb1",
"name": "Slack",
"type": "n8n-nodes-base.slack",
"position": [
260,
1760
],
"webhookId": "070511aa-315a-4533-9c71-c820cef4b633",
"parameters": {
"otherOptions": {}
},
"typeVersion": 2.3
},
{
"id": "ecc1b21c-e3b0-40ae-9e21-9b09f69db3cf",
"name": "Jira Software",
"type": "n8n-nodes-base.jira",
"position": [
260,
1600
],
"parameters": {
"project": {
"__rl": true,
"mode": "list",
"value": ""
},
"summary": "=Dead feature flag: {{$json.deadFlag}}",
"issueType": {
"__rl": true,
"mode": "list",
"value": ""
},
"additionalFields": {}
},
"typeVersion": 1
},
{
"id": "566e7571-2423-4e4b-9edf-dea23b9e8fae",
"name": "HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"position": [
240,
1360
],
"parameters": {
"url": "https://app.launchdarkly.com/api/v2/flags/default",
"options": {},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "",
"value": ""
}
]
}
},
"typeVersion": 4.2,
"alwaysOutputData": false
},
{
"id": "afb07c42-6687-423b-9ccb-739768aa0c4f",
"name": "未使用フラグの検出",
"type": "n8n-nodes-base.code",
"position": [
-420,
1680
],
"parameters": {
"jsCode": "// 1. Extract LaunchDarkly flags array from input\nconst ldItems = $input.all()[0]?.json?.items || [];\n\n// 2. Extract code flags from another input node named 'Code Flags'\nconst codeFlags = $('Detect flags').all().map(item => item.json.flag);\n\n// 3. Filter dead flags from LD\nconst deadFlags = ldItems.filter(ldFlag => {\n const isUsedInCode = codeFlags.includes(ldFlag.key);\n\n if (isUsedInCode) return false;\n\n const prod = ldFlag.environments?.production || {};\n const test = ldFlag.environments?.test || {};\n\n const archivedEverywhere = prod.archived && test.archived;\n const offInProd = prod.on === false;\n\n return archivedEverywhere || offInProd;\n});\n\n// 4. Return as array\nreturn deadFlags.map(flag => ({\n json: {\n deadFlag: flag.key,\n reason: flag.environments?.production?.archived\n ? 'Archived'\n : 'Off in Production'\n }\n}));\n"
},
"typeVersion": 2,
"alwaysOutputData": true
},
{
"id": "75abe5e7-051f-4b87-8329-d10d87ce2b93",
"name": "フラグの検知",
"type": "n8n-nodes-base.code",
"position": [
20,
1360
],
"parameters": {
"jsCode": "const pattern = /(ENABLE_[A-Z0-9_]+)/g;\nconst flags = new Set();\n\nfor (const item of $input.all()) {\n const content = item.json.content || ''; // Assumes content was previously fetched\n let match;\n while ((match = pattern.exec(content)) !== null) {\n flags.add(match[1]);\n }\n}\n\nreturn Array.from(flags).map(flag => ({ json: { flag } }));"
},
"typeVersion": 2,
"alwaysOutputData": true
},
{
"id": "82ee43c2-85c4-4e36-b0ca-0c848266c6de",
"name": "付箋",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1020,
1240
],
"parameters": {
"width": 500,
"height": 700,
"content": "**Purpose:**\nAutomatically find unused (“dead”) feature flags in an Android Kotlin/Java codebase and notify the team.\n\n**Core Logic:**\n\n1. **Weekly trigger** runs the check.\n2. **GitLab** → fetch code & extract used flags.\n3. **LaunchDarkly API** → fetch all flags & statuses.\n4. Compare lists → identify flags not in code and either archived or off in production.\n5. Save results to **Google Sheets**.\n6. If dead flags found → create **Jira tickets** + send **Slack alerts**.\n\n\n**Outcome:**\nKeeps feature flags clean, reduces technical debt, and informs the team automatically.\n"
},
"typeVersion": 1
},
{
"id": "ce6edc27-0f97-45a9-b36d-ad294963cfac",
"name": "付箋1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-500,
1240
],
"parameters": {
"color": 4,
"width": 960,
"height": 700,
"content": "## Catalog Android (Kotlin/Java) feature flags and sweep dead flags vs LaunchDarkly (weekly) → Sheets + Jira + PR + Slack"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "97e8bc6b-a717-4a64-a148-620c2991a8fc",
"connections": {
"70dfcf7f-3d82-44d6-9ea2-ef550b5496f4": {
"main": [
[
{
"node": "75abe5e7-051f-4b87-8329-d10d87ce2b93",
"type": "main",
"index": 0
}
]
]
},
"75abe5e7-051f-4b87-8329-d10d87ce2b93": {
"main": [
[
{
"node": "566e7571-2423-4e4b-9edf-dea23b9e8fae",
"type": "main",
"index": 0
}
]
]
},
"566e7571-2423-4e4b-9edf-dea23b9e8fae": {
"main": [
[
{
"node": "afb07c42-6687-423b-9ccb-739768aa0c4f",
"type": "main",
"index": 0
}
]
]
},
"13799fe3-a8d0-4dc2-924f-a5c53c17dea5": {
"main": [
[
{
"node": "edcaa1e6-4fd2-4b06-93b5-b9219bbba407",
"type": "main",
"index": 0
}
]
]
},
"afb07c42-6687-423b-9ccb-739768aa0c4f": {
"main": [
[
{
"node": "13799fe3-a8d0-4dc2-924f-a5c53c17dea5",
"type": "main",
"index": 0
}
]
]
},
"edcaa1e6-4fd2-4b06-93b5-b9219bbba407": {
"main": [
[
{
"node": "ecc1b21c-e3b0-40ae-9e21-9b09f69db3cf",
"type": "main",
"index": 0
}
],
[
{
"node": "958b3c35-f1ea-4ef4-8c7c-3a69869e4eb1",
"type": "main",
"index": 0
}
]
]
},
"e603fbcb-275a-4356-acbf-d70a219f975c": {
"main": [
[
{
"node": "70dfcf7f-3d82-44d6-9ea2-ef550b5496f4",
"type": "main",
"index": 0
}
]
]
}
}
}よくある質問
このワークフローの使い方は?
上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。
このワークフローはどんな場面に適していますか?
中級 - DevOps, マルチモーダルAI
有料ですか?
このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。
関連ワークフロー
Googleスheetsからの仕事の公開の期限切れチェックと再通知のためにHTTP Last-Modifiedを使用
Google Sheets、HTTP チェック、Gmail を使った求人情報掲載期限の自動提醒
If
Set
Code
+
If
Set
Code
19 ノードWeblineIndia
人事
Google Sheets から Slacks へのインタビュー後フィードバックアラート(メールバックアップ含む)
Google Sheets、Slack、Gmailを使った面接後フィードバックリマインダーの自動化
If
Gmail
Slack
+
If
Gmail
Slack
9 ノードWeblineIndia
人事
スマートワークフロー保守システム
スマートAIフィルタリングとGoogle Workspace統合を備えたスマートワークフローメンテナンスシステム
If
N8n
Code
+
If
N8n
Code
42 ノードJimmy Gay
DevOps
Groq、Gemini、Slack承認システムを使用してRSSからMediumへの公開を自動化
Groq、Gemini、Slack承認システムを用いたRSSからMediumへの自動公開プロセス
If
Set
Code
+
If
Set
Code
41 ノードObisDev
コンテンツ作成
DocuSign と Trello を使用した自動候補者管理とフィードバックシステム
Slack、DocuSign、Trello、Gmail 通知を使った自動化採用プロセス
If
Code
Wait
+
If
Code
Wait
29 ノードMarth
人事
毎日誕生日祝賀(コードノード最終版)
NASA画像、GPT-4、Gmail、Slackを使用した自動太空テーマ誕生日メール
If
Code
Gmail
+
If
Code
Gmail
17 ノードYanagi Chinatsu
個人の生産性
ワークフロー情報
難易度
中級
ノード数11
カテゴリー2
ノードタイプ9
作成者
WeblineIndia
@weblineindiaA Leading Software Engineering, Consulting & Outsourcing Services Company in USA & India serving Clients Globally since 1999.
外部リンク
n8n.ioで表示 →
このワークフローを共有