{"id":"5517863e-d32f-4b37-b025-36d3e04506f4","shortId":"3vtaX6","kind":"skill","title":"embed-ci-setup","tagline":"Quickly create a CI Pipeline for embedded repositories (SonarQube incremental C-language scanning). Triggers when the user says \"add a Pipeline to this repo\", \"create CI configuration\", \"integrate SonarQube\", \"embedded project needs a Pipeline\", or when a repo has no .gitlab-ci.y","description":"# embed-ci-setup\n\nQuickly create a GitLab CI Pipeline for embedded (C language) repositories with SonarQube incremental code scanning.\n\n## Description\n\nEmbedded team rule: Repositories without a Pipeline cannot merge MRs. This Skill helps embedded engineers create a standard CI Pipeline for their repository within minutes, including:\n\n- MR-triggered SonarQube incremental scanning (scans only `.c` / `.h` files changed in this MR)\n- Quality Gate check (shows a warning on failure, does not block the MR)\n- Dynamically generated `sonar-project.properties` (project key auto-generated from the repository path)\n\n**Applicable scenarios:**\n\n- Embedded repository has no Pipeline and needs one quickly\n- Existing `.gitlab-ci.yml` repository needs SonarQube scanning added\n- All embedded projects primarily using C language\n\n**Not applicable:**\n\n- Non-C language projects (Go, Python, Java, etc. should use the global SonarQube template)\n- CI workflows requiring compilation builds (this Skill only does source-code static scanning)\n\n## Rules\n\n### Rule 1 — Environment Constraints (must understand)\n\nAll embedded repositories run CI on the company's unified GitLab platform, with these constraints:\n\n| Constraint | Description |\n|------|------|\n| CI entry point | Managed by `your-org/ci-templates`'s `entrypoint.yml`, which auto-includes the business repository's `.gitlab-ci.yml` |\n| Custom stages prohibited | Do not declare `stages:` in `.gitlab-ci.yml`; use GitLab default stages. Custom stages that do not include `test` will cause pipeline creation failures |\n| include method | Must use `include: project` rather than `include: local`, because the CI entry point is in an external repository and `local` resolves to the wrong repository |\n| Runner tag | Use `sonar-scanner` |\n| Docker image | Must specify `image: harbor.example.com/tools/embed-quality:v1.2.0`; runner uses Kubernetes executor |\n| SonarQube token | Injected via GitLab CI/CD Variable `SONAR_USER_TOKEN`; project admin must configure in advance |\n| SonarQube server | `https://sonarqube.example.com` |\n| No heredoc in YAML | Do not use `<<EOF ... EOF` within `script: \\|` blocks — it causes YAML parsing errors; use `echo` line by line instead |\n\n### Rule 2 — Execution Flow\n\nAfter receiving the user's request, execute the following steps:\n\n**Step 1: Check current repository status**\n\n```bash\n# check if .gitlab-ci.yml exists\nls .gitlab-ci.yml 2>/dev/null\n\n# check if ci/ directory exists\nls ci/sonar-analysis-embed.yml 2>/dev/null\n\n# check if .gitignore has sonar-project.properties\ngrep \"sonar-project.properties\" .gitignore 2>/dev/null\n```\n\n**Step 2: Decide action based on check results**\n\n| .gitlab-ci.yml | ci/sonar-analysis-embed.yml | Action |\n|----------------|----------------------------|------|\n| Does not exist | Does not exist | Create both files (Rule 3 + Rule 4) |\n| Exists | Does not exist | Only create `ci/sonar-analysis-embed.yml` (Rule 4), add include to `.gitlab-ci.yml` (Rule 5) |\n| Exists | Exists | Verify configuration is correct; no action needed |\n\n**Step 3: Update .gitignore**\n\nIf `.gitignore` does not contain `/sonar-project.properties`, add it.\n\n**Step 4: Prompt user to check GitLab CI/CD Variables**\n\nInform the user to confirm that `SONAR_USER_TOKEN` is configured in the project's GitLab **Settings → CI/CD → Variables**.\n\n### Rule 3 — Generate .gitlab-ci.yml (when no existing file)\n\nWhen the repository has no `.gitlab-ci.yml`, generate the following content:\n\n```yaml\ninclude:\n  - project: $CI_PROJECT_PATH\n    ref: $CI_COMMIT_REF_NAME\n    file: ci/sonar-analysis-embed.yml\n\ndefault:\n  tags:\n    - sonar-scanner\n\npass:\n  stage: test\n  script:\n    - echo \"CI pass\"\n```\n\nKey points:\n- **Do not declare `stages:`**; use GitLab defaults\n- The `pass` job uses `stage: test` to ensure the pipeline has a runnable job in non-MR scenarios\n- `include` uses `project: $CI_PROJECT_PATH` + `ref: $CI_COMMIT_REF_NAME`\n\n### Rule 4 — Generate ci/sonar-analysis-embed.yml\n\nCreate the `ci/` directory and generate the following file:\n\n```yaml\n# ============================================================================\n# SonarQube Incremental Analysis Job\n# Triggered on Merge Request events, scans only changed C files (.c/.h)\n#\n# Requires: SONAR_USER_TOKEN configured in GitLab CI/CD Variables\n# ============================================================================\n\nsonar-analysis:\n  stage: test\n  tags:\n    - sonar-scanner\n  image: harbor.example.com/tools/embed-quality:v1.2.0\n  variables:\n    GIT_DEPTH: \"0\"\n    GIT_STRATEGY: fetch\n    SONAR_AUTH_TOKEN: \"${SONAR_USER_TOKEN}\"\n  before_script:\n    - git config --global --add safe.directory \"${CI_PROJECT_DIR}\"\n  script:\n    - |\n      echo \"======================================\"\n      echo \"SonarQube Incremental Analysis\"\n      echo \"  Source: ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}\"\n      echo \"  Target: ${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}\"\n      echo \"======================================\"\n\n      # Step 1: collect changed C files (.c/.h), exclude deleted files\n      TARGET_BRANCH=\"origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}\"\n      SOURCE_BRANCH=\"origin/${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}\"\n      CHANGED_FILES=$(git diff --name-only --diff-filter=d \"${TARGET_BRANCH}...${SOURCE_BRANCH}\" -- '*.c' '*.h' | paste -sd ',' -)\n\n      if [ -z \"${CHANGED_FILES}\" ]; then\n        echo \"No C files (.c/.h) changed in this MR, skipping SonarQube analysis.\"\n        exit 0\n      fi\n\n      echo \"Changed C files:\"\n      echo \"${CHANGED_FILES}\" | tr ',' '\\n' | sed 's/^/  - /'\n\n      # Step 2: generate project key from CI_PROJECT_PATH\n      # e.g. rockchip_rk3576/buildroot -> rockchip_rk3576-buildroot\n      PROJECT_KEY=$(echo \"${CI_PROJECT_PATH}\" | tr '/' '-')\n      echo \"Project Key: ${PROJECT_KEY}\"\n\n      # Step 3: generate sonar-project.properties\n      PROPS=\"${CI_PROJECT_DIR}/sonar-project.properties\"\n      {\n        echo \"sonar.projectKey=${PROJECT_KEY}\"\n        echo \"sonar.projectName=${PROJECT_KEY}\"\n        echo \"sonar.projectVersion=1.0\"\n        echo \"sonar.sources=.\"\n        echo \"sonar.sourceEncoding=UTF-8\"\n        echo \"sonar.language=c\"\n        echo \"sonar.inclusions=${CHANGED_FILES}\"\n        echo \"sonar.scm.provider=git\"\n        echo \"sonar.host.url=https://sonarqube.example.com\"\n      } > \"${PROPS}\"\n\n      echo \"======================================\"\n      echo \"Generated sonar-project.properties:\"\n      cat \"${CI_PROJECT_DIR}/sonar-project.properties\"\n      echo \"======================================\"\n\n      # Step 4: run sonar-scanner with quality gate check\n      sonar-scanner -Dsonar.token=\"${SONAR_AUTH_TOKEN}\" -Dsonar.qualitygate.wait=true\n  allow_failure: true\n  rules:\n    - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n```\n\n### Rule 5 — Add include to existing .gitlab-ci.yml\n\nWhen the repository already has a `.gitlab-ci.yml`, add the include configuration at the top of the file.\n\n**Check items:**\n\n1. If there is already an `include:` section, append one entry:\n```yaml\ninclude:\n  # ... existing includes ...\n  - project: $CI_PROJECT_PATH\n    ref: $CI_COMMIT_REF_NAME\n    file: ci/sonar-analysis-embed.yml\n```\n\n2. If there is no `include:` section, add at the very top of the file:\n```yaml\ninclude:\n  - project: $CI_PROJECT_PATH\n    ref: $CI_COMMIT_REF_NAME\n    file: ci/sonar-analysis-embed.yml\n```\n\n3. **Do not modify** existing `stages:`, `default:`, other jobs, or any other configuration\n\n### Rule 6 — Notify User After Completion\n\nAfter generating files, output the following information:\n\n```\nFiles generated:\n  - .gitlab-ci.yml (created / include updated)\n  - ci/sonar-analysis-embed.yml\n  - .gitignore (sonar-project.properties added)\n\nBefore use, please confirm:\n  1. SONAR_USER_TOKEN is configured in GitLab project Settings → CI/CD → Variables\n  2. Commit these files to the branch; SonarQube scan will auto-trigger when an MR is created\n  3. Scan results can be viewed at https://sonarqube.example.com\n```\n\n## Examples\n\n### Bad\n\n```\nUser: \"Add a Pipeline to this embedded repo\"\nAI: Declares stages: [build, test, deploy] in .gitlab-ci.yml, uses include: local to reference files,\n    and uses heredoc in the script to generate sonar-project.properties\n→ Pipeline creation fails: stages missing test (ci:init requires it), include: local resolves to wrong repo, heredoc causes YAML parse error\n```\n\n```\nUser: \"This repo already has .gitlab-ci.yml, help me add SonarQube\"\nAI: Overwrote the user's original .gitlab-ci.yml, removing existing job configurations\n→ The user's existing CI workflow is broken\n```\n\n### Good\n\n```\nUser: \"Add a Pipeline to this embedded repo\"\nAI: Check finds no .gitlab-ci.yml → generates .gitlab-ci.yml (no stages declared, uses defaults)\n    + ci/sonar-analysis-embed.yml (uses include: project, specifies image, echo writes properties)\n    + .gitignore adds sonar-project.properties\n    → Prompts user to check SONAR_USER_TOKEN configuration\n```\n\n```\nUser: \"This repo already has .gitlab-ci.yml, help me add SonarQube\"\nAI: Check finds existing .gitlab-ci.yml, no ci/sonar-analysis-embed.yml\n    → Only creates ci/sonar-analysis-embed.yml\n    → Appends include at top of existing .gitlab-ci.yml without modifying other content\n    → Prompts user to check SONAR_USER_TOKEN configuration\n```","tags":["embed","setup","enterprise","harness","engineering","addxai","agent-skills","ai-agent","ai-engineering","claude-code","code-review","cursor"],"capabilities":["skill","source-addxai","skill-embed-ci-setup","topic-agent-skills","topic-ai-agent","topic-ai-engineering","topic-claude-code","topic-code-review","topic-cursor","topic-devops","topic-enterprise","topic-sre","topic-windsurf"],"categories":["enterprise-harness-engineering"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/addxai/enterprise-harness-engineering/embed-ci-setup","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add addxai/enterprise-harness-engineering","source_repo":"https://github.com/addxai/enterprise-harness-engineering","install_from":"skills.sh"}},"qualityScore":"0.458","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 16 github stars · SKILL.md body (9,245 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T01:02:11.632Z","embedding":null,"createdAt":"2026-04-21T19:04:01.111Z","updatedAt":"2026-04-22T01:02:11.632Z","lastSeenAt":"2026-04-22T01:02:11.632Z","tsv":"'-8':795 '/ci-templates':225 '/dev/null':377,386,396 '/sonar-project.properties':454,778,818 '/tools/embed-quality:v1.2.0':302,617 '0':621,729 '1':195,364,665,876,970 '1.0':789 '2':350,376,385,395,398,743,902,982 '3':418,446,486,771,930,1000 '4':420,429,458,568,821 '5':435,851 '6':944 'action':400,407,443 'ad':154,965 'add':24,430,455,636,852,864,909,1011,1070,1093,1122,1140 'admin':318 'advanc':322 'ai':1018,1072,1100,1142 'allow':839 'alreadi':860,880,1065,1135 'analysi':583,607,646,727 'append':884,1152 'applic':137,163 'auth':626,835 'auto':131,230,993 'auto-gener':130 'auto-includ':229 'auto-trigg':992 'bad':1009 'base':401 'bash':369 'block':122,337 'branch':653,661,675,681,684,690,704,706,988 'broken':1090 'build':183,1021 'buildroot':757 'busi':233 'c':16,62,105,160,166,593,668,707,718,733,798 'c-languag':15 'c/.h':595,670,720 'cannot':78 'cat':814 'caus':258,339,1058 'chang':108,592,667,692,713,721,732,736,801 'check':114,365,370,378,387,403,462,829,874,1101,1127,1143,1166 'ci':3,8,31,48,52,58,89,179,204,217,274,380,506,510,526,559,563,573,638,649,657,677,686,748,761,775,815,844,892,896,920,924,1047,1087 'ci/cd':312,464,483,603,980 'ci/sonar-analysis-embed.yml':384,406,427,515,570,901,929,962,1112,1148,1151 'code':68,190 'collect':666 'commit':511,564,897,925,983 'compani':207 'compil':182 'complet':948 'config':634 'configur':32,320,439,476,600,867,942,975,1082,1131,1170 'confirm':470,969 'constraint':197,214,215 'contain':453 'content':502,1162 'correct':441 'creat':6,30,55,86,414,426,571,959,999,1150 'creation':260,1042 'current':366 'custom':237,250 'd':702 'decid':399 'declar':242,532,1019,1109 'default':248,516,536,936,1111 'delet':672 'deploy':1023 'depth':620 'descript':70,216 'diff':695,700 'diff-filt':699 'dir':640,777,817 'directori':381,574 'docker':295 'dsonar.qualitygate.wait':837 'dsonar.token':833 'dynam':125 'e.g':751 'echo':344,525,642,643,647,655,663,716,731,735,760,765,779,783,787,790,792,796,799,803,806,810,811,819,1118 'emb':2,51 'embed':11,35,61,71,84,139,156,201,1016,1098 'embed-ci-setup':1,50 'engin':85 'ensur':544 'entri':218,275,886 'entrypoint.yml':227 'environ':196 'eof':333,334 'error':342,1061 'etc':172 'event':589,849 'exampl':1008 'exclud':671 'execut':351,359 'executor':306 'exist':148,373,382,410,413,421,424,436,437,491,855,889,934,1080,1086,1145,1157 'exit':728 'extern':280 'fail':1043 'failur':119,261,840 'fetch':624 'fi':730 'file':107,416,492,514,579,594,669,673,693,714,719,734,737,802,873,900,916,928,951,956,985,1031 'filter':701 'find':1102,1144 'flow':352 'follow':361,501,578,954 'gate':113,828 'generat':126,132,487,499,569,576,744,772,812,950,957,1039,1105 'git':619,622,633,694,805 'gitignor':389,394,448,450,963,1121 'gitlab':47,57,210,247,311,463,481,535,602,977 'gitlab-ci':46 'gitlab-ci.yml':149,236,245,372,375,405,433,488,498,856,863,958,1025,1067,1078,1104,1106,1137,1146,1158 'global':176,635 'go':169 'good':1091 'grep':392 'h':106,708 'harbor.example.com':301,616 'harbor.example.com/tools/embed-quality:v1.2.0':300,615 'help':83,1068,1138 'heredoc':327,1034,1057 'imag':296,299,614,1117 'includ':96,231,255,262,266,270,431,504,556,853,866,882,888,890,907,918,960,1027,1051,1114,1153 'increment':14,67,101,582,645 'inform':466,955 'init':1048 'inject':309 'instead':348 'integr':33 'item':875 'java':171 'job':539,550,584,938,1081 'key':129,528,746,759,767,769,782,786 'kubernet':305 'languag':17,63,161,167 'line':345,347 'local':271,283,1028,1052 'ls':374,383 'manag':220 'merg':79,587,650,658,678,687,847 'method':263 'minut':95 'miss':1045 'modifi':933,1160 'mr':98,111,124,554,724,997 'mr-trigger':97 'mrs':80 'must':198,264,297,319 'n':739 'name':513,566,654,662,682,691,697,899,927 'name-on':696 'need':37,145,151,444 'non':165,553 'non-c':164 'non-mr':552 'notifi':945 'one':146,885 'org':224 'origin':676,685,1077 'output':952 'overwrot':1073 'pars':341,1060 'pass':521,527,538 'past':709 'path':136,508,561,750,763,894,922 'pipelin':9,26,39,59,77,90,143,259,546,845,1013,1041,1095 'platform':211 'pleas':968 'point':219,276,529 'primarili':158 'prohibit':239 'project':36,128,157,168,267,317,479,505,507,558,560,639,745,749,758,762,766,768,776,781,785,816,891,893,919,921,978,1115 'prompt':459,1124,1163 'prop':774,809 'properti':1120 'python':170 'qualiti':112,827 'quick':5,54,147 'rather':268 'receiv':354 'ref':509,512,562,565,895,898,923,926 'refer':1030 'remov':1079 'repo':29,43,1017,1056,1064,1099,1134 'repositori':12,64,74,93,135,140,150,202,234,281,288,367,495,859 'request':358,588,651,659,679,688,848 'requir':181,596,1049 'resolv':284,1053 'result':404,1002 'rk3576':756 'rk3576-buildroot':755 'rk3576/buildroot':753 'rockchip':752,754 'rule':73,193,194,349,417,419,428,434,485,567,842,850,943 'run':203,822 'runnabl':549 'runner':289,303 'safe.directory':637 'say':23 'scan':18,69,102,103,153,192,590,990,1001 'scanner':294,520,613,825,832 'scenario':138,555 'script':336,524,632,641,1037 'sd':710 'section':883,908 'sed':740 'server':324 'set':482,979 'setup':4,53 'show':115 'skill':82,185 'skill-embed-ci-setup' 'skip':725 'sonar':293,314,472,519,597,606,612,625,628,824,831,834,971,1128,1167 'sonar-analysi':605 'sonar-project.properties':127,391,393,773,813,964,1040,1123 'sonar-scann':292,518,611,823,830 'sonar.host.url':807 'sonar.inclusions':800 'sonar.language':797 'sonar.projectkey':780 'sonar.projectname':784 'sonar.projectversion':788 'sonar.scm.provider':804 'sonar.sourceencoding':793 'sonar.sources':791 'sonarqub':13,34,66,100,152,177,307,323,581,644,726,989,1071,1141 'sonarqube.example.com':325,808,1007 'sourc':189,648,652,683,689,705,846 'source-addxai' 'source-cod':188 'specifi':298,1116 'stage':238,243,249,251,522,533,541,608,935,1020,1044,1108 'standard':88 'static':191 'status':368 'step':362,363,397,445,457,664,742,770,820 'strategi':623 'tag':290,517,610 'target':656,660,674,680,703 'team':72 'templat':178 'test':256,523,542,609,1022,1046 'token':308,316,474,599,627,630,836,973,1130,1169 'top':870,913,1155 'topic-agent-skills' 'topic-ai-agent' 'topic-ai-engineering' 'topic-claude-code' 'topic-code-review' 'topic-cursor' 'topic-devops' 'topic-enterprise' 'topic-sre' 'topic-windsurf' 'tr':738,764 'trigger':19,99,585,994 'true':838,841 'understand':199 'unifi':209 'updat':447,961 'use':159,174,246,265,291,304,332,343,534,540,557,967,1026,1033,1110,1113 'user':22,315,356,460,468,473,598,629,946,972,1010,1062,1075,1084,1092,1125,1129,1132,1164,1168 'utf':794 'variabl':313,465,484,604,618,981 'verifi':438 'via':310 'view':1005 'warn':117 'within':94,335 'without':75,1159 'workflow':180,1088 'write':1119 'wrong':287,1055 'y':49 'yaml':329,340,503,580,887,917,1059 'your-org':222 'z':712","prices":[{"id":"d733e1f5-7666-40fc-bf08-98753f4a6515","listingId":"5517863e-d32f-4b37-b025-36d3e04506f4","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"addxai","category":"enterprise-harness-engineering","install_from":"skills.sh"},"createdAt":"2026-04-21T19:04:01.111Z"}],"sources":[{"listingId":"5517863e-d32f-4b37-b025-36d3e04506f4","source":"github","sourceId":"addxai/enterprise-harness-engineering/embed-ci-setup","sourceUrl":"https://github.com/addxai/enterprise-harness-engineering/tree/main/skills/embed-ci-setup","isPrimary":false,"firstSeenAt":"2026-04-21T19:04:01.111Z","lastSeenAt":"2026-04-22T01:02:11.632Z"}],"details":{"listingId":"5517863e-d32f-4b37-b025-36d3e04506f4","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"addxai","slug":"embed-ci-setup","github":{"repo":"addxai/enterprise-harness-engineering","stars":16,"topics":["agent-skills","ai-agent","ai-engineering","claude-code","code-review","cursor","devops","enterprise","sre","windsurf"],"license":"apache-2.0","html_url":"https://github.com/addxai/enterprise-harness-engineering","pushed_at":"2026-04-17T08:57:37Z","description":"Enterprise-grade AI Agent Skills for software development, DevOps, SRE, security, and product teams. Compatible with Claude Code, Cursor, Windsurf, Gemini CLI, GitHub Copilot, and 30+ AI coding agents.","skill_md_sha":"2413e2da421e2c01a710ebf462e55fe775a8fdb2","skill_md_path":"skills/embed-ci-setup/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/addxai/enterprise-harness-engineering/tree/main/skills/embed-ci-setup"},"layout":"multi","source":"github","category":"enterprise-harness-engineering","frontmatter":{"name":"embed-ci-setup","description":"Quickly create a CI Pipeline for embedded repositories (SonarQube incremental C-language scanning). Triggers when the user says \"add a Pipeline to this repo\", \"create CI configuration\", \"integrate SonarQube\", \"embedded project needs a Pipeline\", or when a repo has no .gitlab-ci.yml and cannot merge MRs."},"skills_sh_url":"https://skills.sh/addxai/enterprise-harness-engineering/embed-ci-setup"},"updatedAt":"2026-04-22T01:02:11.632Z"}}