[{"data":1,"prerenderedAt":1600},["ShallowReactive",2],{"doc-page:\u002Fdocs\u002Fgithub-actions":3},{"doc":4,"prev":1562,"next":1569,"resolvedType":8,"readingMinutes":143,"audience":1576,"checklist":1580,"related":1584},{"path":5,"title":6,"description":7,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":12,"publishedAt":12,"icon":13,"body":14},"\u002Fdocs\u002Fgithub-actions","GitHub Actions 入门","CI\u002FCD 工作流配置、自动测试、自动部署与常用 Action 推荐","article",null,"infra-deployment","服务器与部署","2026-02-27","i-carbon-cloud",{"type":15,"value":16,"toc":1537},"minimark",[17,21,32,35,39,42,58,61,64,67,78,81,90,93,100,305,308,412,415,420,619,623,806,810,984,988,1108,1112,1115,1118,1140,1143,1197,1201,1204,1226,1229,1257,1261,1264,1290,1298,1302,1390,1393,1396,1413,1416,1431,1434,1453,1456,1464,1475,1478,1504,1507,1533],[18,19,6],"h1",{"id":20},"github-actions-入门",[22,23,24,31],"p",{},[25,26,30],"a",{"href":27,"rel":28},"https:\u002F\u002Fgithub.com\u002Ffeatures\u002Factions",[29],"nofollow","GitHub Actions"," 是 GitHub 内置的 CI\u002FCD 平台，通过 YAML 配置自动化工作流。",[22,33,34],{},"这页更适合当作“团队自动化起步手册”来用：先把持续集成跑通，再决定是否把部署、发版、定时任务也收进仓库。很多仓库一开始就把 CI\u002FCD 全塞进一个工作流，后面往往会变成难改、难排障、改一个步骤全局受影响。",[36,37,38],"h2",{"id":38},"推荐落地顺序",[22,40,41],{},"建议按下面的顺序逐步接入，而不是一次写满所有能力：",[43,44,45,49,52,55],"ol",{},[46,47,48],"li",{},"先做最小 CI：安装依赖、类型检查、测试、构建",[46,50,51],{},"再加缓存与矩阵测试，提升速度和兼容性",[46,53,54],{},"然后拆出部署工作流，避免与 CI 混在一起",[46,56,57],{},"最后再补 Release、定时任务、自动清理等辅助流程",[22,59,60],{},"如果项目已经接入平台自带的 Git 自动部署（例如 Cloudflare Pages \u002F Vercel \u002F Netlify），那 GitHub Actions 往往更适合负责“检查与门禁”，而不是重复做第二次部署。",[36,62,63],{"id":63},"工作流拆分建议",[22,65,66],{},"常见的目录结构如下：",[68,69,75],"pre",{"className":70,"code":72,"language":73,"meta":74},[71],"language-text",".github\u002Fworkflows\u002F\n  ci.yml            # lint \u002F test \u002F build\n  deploy.yml        # 部署到服务器或平台\n  release.yml       # tag \u002F release note \u002F artifact\n  nightly.yml       # 定时任务、巡检、备份\n","text","",[76,77,72],"code",{"__ignoreMap":74},[22,79,80],{},"拆分的核心好处有两个：",[82,83,84,87],"ul",{},[46,85,86],{},"改测试流程时，不会误伤部署逻辑",[46,88,89],{},"出问题时能快速判断是“质量检查失败”还是“发布链路失败”",[36,91,92],{"id":92},"基本结构",[22,94,95,96,99],{},"在仓库中创建 ",[76,97,98],{},".github\u002Fworkflows\u002Fci.yml","：",[68,101,105],{"className":102,"code":103,"language":104,"meta":74,"style":74},"language-yaml shiki shiki-themes github-light github-dark","name: CI\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-node@v4\n        with:\n          node-version: 22\n      - run: npm ci\n      - run: npm run build\n      - run: npm test\n","yaml",[76,106,107,124,131,141,149,164,172,183,188,196,204,215,223,237,249,257,268,281,293],{"__ignoreMap":74},[108,109,112,116,120],"span",{"class":110,"line":111},"line",1,[108,113,115],{"class":114},"s9eBZ","name",[108,117,119],{"class":118},"sVt8B",": ",[108,121,123],{"class":122},"sZZnC","CI\n",[108,125,127],{"class":110,"line":126},2,[108,128,130],{"emptyLinePlaceholder":129},true,"\n",[108,132,134,138],{"class":110,"line":133},3,[108,135,137],{"class":136},"sj4cs","on",[108,139,140],{"class":118},":\n",[108,142,144,147],{"class":110,"line":143},4,[108,145,146],{"class":114},"  push",[108,148,140],{"class":118},[108,150,152,155,158,161],{"class":110,"line":151},5,[108,153,154],{"class":114},"    branches",[108,156,157],{"class":118},": [",[108,159,160],{"class":122},"main",[108,162,163],{"class":118},"]\n",[108,165,167,170],{"class":110,"line":166},6,[108,168,169],{"class":114},"  pull_request",[108,171,140],{"class":118},[108,173,175,177,179,181],{"class":110,"line":174},7,[108,176,154],{"class":114},[108,178,157],{"class":118},[108,180,160],{"class":122},[108,182,163],{"class":118},[108,184,186],{"class":110,"line":185},8,[108,187,130],{"emptyLinePlaceholder":129},[108,189,191,194],{"class":110,"line":190},9,[108,192,193],{"class":114},"jobs",[108,195,140],{"class":118},[108,197,199,202],{"class":110,"line":198},10,[108,200,201],{"class":114},"  build",[108,203,140],{"class":118},[108,205,207,210,212],{"class":110,"line":206},11,[108,208,209],{"class":114},"    runs-on",[108,211,119],{"class":118},[108,213,214],{"class":122},"ubuntu-latest\n",[108,216,218,221],{"class":110,"line":217},12,[108,219,220],{"class":114},"    steps",[108,222,140],{"class":118},[108,224,226,229,232,234],{"class":110,"line":225},13,[108,227,228],{"class":118},"      - ",[108,230,231],{"class":114},"uses",[108,233,119],{"class":118},[108,235,236],{"class":122},"actions\u002Fcheckout@v4\n",[108,238,240,242,244,246],{"class":110,"line":239},14,[108,241,228],{"class":118},[108,243,231],{"class":114},[108,245,119],{"class":118},[108,247,248],{"class":122},"actions\u002Fsetup-node@v4\n",[108,250,252,255],{"class":110,"line":251},15,[108,253,254],{"class":114},"        with",[108,256,140],{"class":118},[108,258,260,263,265],{"class":110,"line":259},16,[108,261,262],{"class":114},"          node-version",[108,264,119],{"class":118},[108,266,267],{"class":136},"22\n",[108,269,271,273,276,278],{"class":110,"line":270},17,[108,272,228],{"class":118},[108,274,275],{"class":114},"run",[108,277,119],{"class":118},[108,279,280],{"class":122},"npm ci\n",[108,282,284,286,288,290],{"class":110,"line":283},18,[108,285,228],{"class":118},[108,287,275],{"class":114},[108,289,119],{"class":118},[108,291,292],{"class":122},"npm run build\n",[108,294,296,298,300,302],{"class":110,"line":295},19,[108,297,228],{"class":118},[108,299,275],{"class":114},[108,301,119],{"class":118},[108,303,304],{"class":122},"npm test\n",[36,306,307],{"id":307},"触发条件",[68,309,311],{"className":102,"code":310,"language":104,"meta":74,"style":74},"on:\n  push:\n    branches: [main, develop]\n    paths:\n      - \"src\u002F**\"\n      - \"package.json\"\n  pull_request:\n    branches: [main]\n  schedule:\n    - cron: \"0 0 * * 1\" # 每周一 UTC 0:00\n  workflow_dispatch: # 手动触发\n",[76,312,313,319,325,341,348,355,362,368,378,385,402],{"__ignoreMap":74},[108,314,315,317],{"class":110,"line":111},[108,316,137],{"class":136},[108,318,140],{"class":118},[108,320,321,323],{"class":110,"line":126},[108,322,146],{"class":114},[108,324,140],{"class":118},[108,326,327,329,331,333,336,339],{"class":110,"line":133},[108,328,154],{"class":114},[108,330,157],{"class":118},[108,332,160],{"class":122},[108,334,335],{"class":118},", ",[108,337,338],{"class":122},"develop",[108,340,163],{"class":118},[108,342,343,346],{"class":110,"line":143},[108,344,345],{"class":114},"    paths",[108,347,140],{"class":118},[108,349,350,352],{"class":110,"line":151},[108,351,228],{"class":118},[108,353,354],{"class":122},"\"src\u002F**\"\n",[108,356,357,359],{"class":110,"line":166},[108,358,228],{"class":118},[108,360,361],{"class":122},"\"package.json\"\n",[108,363,364,366],{"class":110,"line":174},[108,365,169],{"class":114},[108,367,140],{"class":118},[108,369,370,372,374,376],{"class":110,"line":185},[108,371,154],{"class":114},[108,373,157],{"class":118},[108,375,160],{"class":122},[108,377,163],{"class":118},[108,379,380,383],{"class":110,"line":190},[108,381,382],{"class":114},"  schedule",[108,384,140],{"class":118},[108,386,387,390,393,395,398],{"class":110,"line":198},[108,388,389],{"class":118},"    - ",[108,391,392],{"class":114},"cron",[108,394,119],{"class":118},[108,396,397],{"class":122},"\"0 0 * * 1\"",[108,399,401],{"class":400},"sJ8bj"," # 每周一 UTC 0:00\n",[108,403,404,407,409],{"class":110,"line":206},[108,405,406],{"class":114},"  workflow_dispatch",[108,408,119],{"class":118},[108,410,411],{"class":400},"# 手动触发\n",[36,413,414],{"id":414},"常用模板",[416,417,419],"h3",{"id":418},"nodejs-项目","Node.js 项目",[68,421,423],{"className":102,"code":422,"language":104,"meta":74,"style":74},"name: CI\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        node-version: [20, 22]\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-node@v4\n        with:\n          node-version: ${{ matrix.node-version }}\n      - uses: pnpm\u002Faction-setup@v4\n        with:\n          version: latest\n      - run: pnpm install --frozen-lockfile\n      - run: pnpm lint\n      - run: pnpm test\n      - run: pnpm build\n",[76,424,425,433,449,453,459,466,474,481,488,505,511,521,531,537,546,557,563,573,584,595,607],{"__ignoreMap":74},[108,426,427,429,431],{"class":110,"line":111},[108,428,115],{"class":114},[108,430,119],{"class":118},[108,432,123],{"class":122},[108,434,435,437,439,442,444,447],{"class":110,"line":126},[108,436,137],{"class":136},[108,438,157],{"class":118},[108,440,441],{"class":122},"push",[108,443,335],{"class":118},[108,445,446],{"class":122},"pull_request",[108,448,163],{"class":118},[108,450,451],{"class":110,"line":133},[108,452,130],{"emptyLinePlaceholder":129},[108,454,455,457],{"class":110,"line":143},[108,456,193],{"class":114},[108,458,140],{"class":118},[108,460,461,464],{"class":110,"line":151},[108,462,463],{"class":114},"  test",[108,465,140],{"class":118},[108,467,468,470,472],{"class":110,"line":166},[108,469,209],{"class":114},[108,471,119],{"class":118},[108,473,214],{"class":122},[108,475,476,479],{"class":110,"line":174},[108,477,478],{"class":114},"    strategy",[108,480,140],{"class":118},[108,482,483,486],{"class":110,"line":185},[108,484,485],{"class":114},"      matrix",[108,487,140],{"class":118},[108,489,490,493,495,498,500,503],{"class":110,"line":190},[108,491,492],{"class":114},"        node-version",[108,494,157],{"class":118},[108,496,497],{"class":136},"20",[108,499,335],{"class":118},[108,501,502],{"class":136},"22",[108,504,163],{"class":118},[108,506,507,509],{"class":110,"line":198},[108,508,220],{"class":114},[108,510,140],{"class":118},[108,512,513,515,517,519],{"class":110,"line":206},[108,514,228],{"class":118},[108,516,231],{"class":114},[108,518,119],{"class":118},[108,520,236],{"class":122},[108,522,523,525,527,529],{"class":110,"line":217},[108,524,228],{"class":118},[108,526,231],{"class":114},[108,528,119],{"class":118},[108,530,248],{"class":122},[108,532,533,535],{"class":110,"line":225},[108,534,254],{"class":114},[108,536,140],{"class":118},[108,538,539,541,543],{"class":110,"line":239},[108,540,262],{"class":114},[108,542,119],{"class":118},[108,544,545],{"class":122},"${{ matrix.node-version }}\n",[108,547,548,550,552,554],{"class":110,"line":251},[108,549,228],{"class":118},[108,551,231],{"class":114},[108,553,119],{"class":118},[108,555,556],{"class":122},"pnpm\u002Faction-setup@v4\n",[108,558,559,561],{"class":110,"line":259},[108,560,254],{"class":114},[108,562,140],{"class":118},[108,564,565,568,570],{"class":110,"line":270},[108,566,567],{"class":114},"          version",[108,569,119],{"class":118},[108,571,572],{"class":122},"latest\n",[108,574,575,577,579,581],{"class":110,"line":283},[108,576,228],{"class":118},[108,578,275],{"class":114},[108,580,119],{"class":118},[108,582,583],{"class":122},"pnpm install --frozen-lockfile\n",[108,585,586,588,590,592],{"class":110,"line":295},[108,587,228],{"class":118},[108,589,275],{"class":114},[108,591,119],{"class":118},[108,593,594],{"class":122},"pnpm lint\n",[108,596,598,600,602,604],{"class":110,"line":597},20,[108,599,228],{"class":118},[108,601,275],{"class":114},[108,603,119],{"class":118},[108,605,606],{"class":122},"pnpm test\n",[108,608,610,612,614,616],{"class":110,"line":609},21,[108,611,228],{"class":118},[108,613,275],{"class":114},[108,615,119],{"class":118},[108,617,618],{"class":122},"pnpm build\n",[416,620,622],{"id":621},"部署到-cloudflare-pages","部署到 Cloudflare Pages",[68,624,626],{"className":102,"code":625,"language":104,"meta":74,"style":74},"name: Deploy\non:\n  push:\n    branches: [main]\n\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-node@v4\n        with:\n          node-version: 22\n      - uses: pnpm\u002Faction-setup@v4\n        with:\n          version: latest\n      - run: pnpm install --frozen-lockfile\n      - run: pnpm build\n      - uses: cloudflare\u002Fwrangler-action@v3\n        with:\n          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}\n          command: pages deploy dist --project-name=my-project\n",[76,627,628,637,643,649,659,663,669,676,684,690,700,710,716,724,734,740,748,758,768,779,785,795],{"__ignoreMap":74},[108,629,630,632,634],{"class":110,"line":111},[108,631,115],{"class":114},[108,633,119],{"class":118},[108,635,636],{"class":122},"Deploy\n",[108,638,639,641],{"class":110,"line":126},[108,640,137],{"class":136},[108,642,140],{"class":118},[108,644,645,647],{"class":110,"line":133},[108,646,146],{"class":114},[108,648,140],{"class":118},[108,650,651,653,655,657],{"class":110,"line":143},[108,652,154],{"class":114},[108,654,157],{"class":118},[108,656,160],{"class":122},[108,658,163],{"class":118},[108,660,661],{"class":110,"line":151},[108,662,130],{"emptyLinePlaceholder":129},[108,664,665,667],{"class":110,"line":166},[108,666,193],{"class":114},[108,668,140],{"class":118},[108,670,671,674],{"class":110,"line":174},[108,672,673],{"class":114},"  deploy",[108,675,140],{"class":118},[108,677,678,680,682],{"class":110,"line":185},[108,679,209],{"class":114},[108,681,119],{"class":118},[108,683,214],{"class":122},[108,685,686,688],{"class":110,"line":190},[108,687,220],{"class":114},[108,689,140],{"class":118},[108,691,692,694,696,698],{"class":110,"line":198},[108,693,228],{"class":118},[108,695,231],{"class":114},[108,697,119],{"class":118},[108,699,236],{"class":122},[108,701,702,704,706,708],{"class":110,"line":206},[108,703,228],{"class":118},[108,705,231],{"class":114},[108,707,119],{"class":118},[108,709,248],{"class":122},[108,711,712,714],{"class":110,"line":217},[108,713,254],{"class":114},[108,715,140],{"class":118},[108,717,718,720,722],{"class":110,"line":225},[108,719,262],{"class":114},[108,721,119],{"class":118},[108,723,267],{"class":136},[108,725,726,728,730,732],{"class":110,"line":239},[108,727,228],{"class":118},[108,729,231],{"class":114},[108,731,119],{"class":118},[108,733,556],{"class":122},[108,735,736,738],{"class":110,"line":251},[108,737,254],{"class":114},[108,739,140],{"class":118},[108,741,742,744,746],{"class":110,"line":259},[108,743,567],{"class":114},[108,745,119],{"class":118},[108,747,572],{"class":122},[108,749,750,752,754,756],{"class":110,"line":270},[108,751,228],{"class":118},[108,753,275],{"class":114},[108,755,119],{"class":118},[108,757,583],{"class":122},[108,759,760,762,764,766],{"class":110,"line":283},[108,761,228],{"class":118},[108,763,275],{"class":114},[108,765,119],{"class":118},[108,767,618],{"class":122},[108,769,770,772,774,776],{"class":110,"line":295},[108,771,228],{"class":118},[108,773,231],{"class":114},[108,775,119],{"class":118},[108,777,778],{"class":122},"cloudflare\u002Fwrangler-action@v3\n",[108,780,781,783],{"class":110,"line":597},[108,782,254],{"class":114},[108,784,140],{"class":118},[108,786,787,790,792],{"class":110,"line":609},[108,788,789],{"class":114},"          apiToken",[108,791,119],{"class":118},[108,793,794],{"class":122},"${{ secrets.CLOUDFLARE_API_TOKEN }}\n",[108,796,798,801,803],{"class":110,"line":797},22,[108,799,800],{"class":114},"          command",[108,802,119],{"class":118},[108,804,805],{"class":122},"pages deploy dist --project-name=my-project\n",[416,807,809],{"id":808},"docker-构建推送","Docker 构建推送",[68,811,813],{"className":102,"code":812,"language":104,"meta":74,"style":74},"name: Docker\non:\n  push:\n    tags: [\"v*\"]\n\njobs:\n  docker:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: docker\u002Fsetup-buildx-action@v3\n      - uses: docker\u002Flogin-action@v3\n        with:\n          registry: ghcr.io\n          username: ${{ github.actor }}\n          password: ${{ secrets.GITHUB_TOKEN }}\n      - uses: docker\u002Fbuild-push-action@v6\n        with:\n          push: true\n          tags: ghcr.io\u002F${{ github.repository }}:${{ github.ref_name }}\n",[76,814,815,824,830,836,848,852,858,865,873,879,889,900,911,917,927,937,947,958,964,974],{"__ignoreMap":74},[108,816,817,819,821],{"class":110,"line":111},[108,818,115],{"class":114},[108,820,119],{"class":118},[108,822,823],{"class":122},"Docker\n",[108,825,826,828],{"class":110,"line":126},[108,827,137],{"class":136},[108,829,140],{"class":118},[108,831,832,834],{"class":110,"line":133},[108,833,146],{"class":114},[108,835,140],{"class":118},[108,837,838,841,843,846],{"class":110,"line":143},[108,839,840],{"class":114},"    tags",[108,842,157],{"class":118},[108,844,845],{"class":122},"\"v*\"",[108,847,163],{"class":118},[108,849,850],{"class":110,"line":151},[108,851,130],{"emptyLinePlaceholder":129},[108,853,854,856],{"class":110,"line":166},[108,855,193],{"class":114},[108,857,140],{"class":118},[108,859,860,863],{"class":110,"line":174},[108,861,862],{"class":114},"  docker",[108,864,140],{"class":118},[108,866,867,869,871],{"class":110,"line":185},[108,868,209],{"class":114},[108,870,119],{"class":118},[108,872,214],{"class":122},[108,874,875,877],{"class":110,"line":190},[108,876,220],{"class":114},[108,878,140],{"class":118},[108,880,881,883,885,887],{"class":110,"line":198},[108,882,228],{"class":118},[108,884,231],{"class":114},[108,886,119],{"class":118},[108,888,236],{"class":122},[108,890,891,893,895,897],{"class":110,"line":206},[108,892,228],{"class":118},[108,894,231],{"class":114},[108,896,119],{"class":118},[108,898,899],{"class":122},"docker\u002Fsetup-buildx-action@v3\n",[108,901,902,904,906,908],{"class":110,"line":217},[108,903,228],{"class":118},[108,905,231],{"class":114},[108,907,119],{"class":118},[108,909,910],{"class":122},"docker\u002Flogin-action@v3\n",[108,912,913,915],{"class":110,"line":225},[108,914,254],{"class":114},[108,916,140],{"class":118},[108,918,919,922,924],{"class":110,"line":239},[108,920,921],{"class":114},"          registry",[108,923,119],{"class":118},[108,925,926],{"class":122},"ghcr.io\n",[108,928,929,932,934],{"class":110,"line":251},[108,930,931],{"class":114},"          username",[108,933,119],{"class":118},[108,935,936],{"class":122},"${{ github.actor }}\n",[108,938,939,942,944],{"class":110,"line":259},[108,940,941],{"class":114},"          password",[108,943,119],{"class":118},[108,945,946],{"class":122},"${{ secrets.GITHUB_TOKEN }}\n",[108,948,949,951,953,955],{"class":110,"line":270},[108,950,228],{"class":118},[108,952,231],{"class":114},[108,954,119],{"class":118},[108,956,957],{"class":122},"docker\u002Fbuild-push-action@v6\n",[108,959,960,962],{"class":110,"line":283},[108,961,254],{"class":114},[108,963,140],{"class":118},[108,965,966,969,971],{"class":110,"line":295},[108,967,968],{"class":114},"          push",[108,970,119],{"class":118},[108,972,973],{"class":136},"true\n",[108,975,976,979,981],{"class":110,"line":597},[108,977,978],{"class":114},"          tags",[108,980,119],{"class":118},[108,982,983],{"class":122},"ghcr.io\u002F${{ github.repository }}:${{ github.ref_name }}\n",[416,985,987],{"id":986},"自动发布-release","自动发布 Release",[68,989,991],{"className":102,"code":990,"language":104,"meta":74,"style":74},"name: Release\non:\n  push:\n    tags: [\"v*\"]\n\njobs:\n  release:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: softprops\u002Faction-gh-release@v2\n        with:\n          generate_release_notes: true\n",[76,992,993,1002,1008,1014,1024,1028,1034,1041,1049,1056,1066,1072,1082,1093,1099],{"__ignoreMap":74},[108,994,995,997,999],{"class":110,"line":111},[108,996,115],{"class":114},[108,998,119],{"class":118},[108,1000,1001],{"class":122},"Release\n",[108,1003,1004,1006],{"class":110,"line":126},[108,1005,137],{"class":136},[108,1007,140],{"class":118},[108,1009,1010,1012],{"class":110,"line":133},[108,1011,146],{"class":114},[108,1013,140],{"class":118},[108,1015,1016,1018,1020,1022],{"class":110,"line":143},[108,1017,840],{"class":114},[108,1019,157],{"class":118},[108,1021,845],{"class":122},[108,1023,163],{"class":118},[108,1025,1026],{"class":110,"line":151},[108,1027,130],{"emptyLinePlaceholder":129},[108,1029,1030,1032],{"class":110,"line":166},[108,1031,193],{"class":114},[108,1033,140],{"class":118},[108,1035,1036,1039],{"class":110,"line":174},[108,1037,1038],{"class":114},"  release",[108,1040,140],{"class":118},[108,1042,1043,1045,1047],{"class":110,"line":185},[108,1044,209],{"class":114},[108,1046,119],{"class":118},[108,1048,214],{"class":122},[108,1050,1051,1054],{"class":110,"line":190},[108,1052,1053],{"class":114},"    permissions",[108,1055,140],{"class":118},[108,1057,1058,1061,1063],{"class":110,"line":198},[108,1059,1060],{"class":114},"      contents",[108,1062,119],{"class":118},[108,1064,1065],{"class":122},"write\n",[108,1067,1068,1070],{"class":110,"line":206},[108,1069,220],{"class":114},[108,1071,140],{"class":118},[108,1073,1074,1076,1078,1080],{"class":110,"line":217},[108,1075,228],{"class":118},[108,1077,231],{"class":114},[108,1079,119],{"class":118},[108,1081,236],{"class":122},[108,1083,1084,1086,1088,1090],{"class":110,"line":225},[108,1085,228],{"class":118},[108,1087,231],{"class":114},[108,1089,119],{"class":118},[108,1091,1092],{"class":122},"softprops\u002Faction-gh-release@v2\n",[108,1094,1095,1097],{"class":110,"line":239},[108,1096,254],{"class":114},[108,1098,140],{"class":118},[108,1100,1101,1104,1106],{"class":110,"line":251},[108,1102,1103],{"class":114},"          generate_release_notes",[108,1105,119],{"class":118},[108,1107,973],{"class":136},[36,1109,1111],{"id":1110},"secrets-配置","Secrets 配置",[22,1113,1114],{},"仓库 Settings → Secrets and variables → Actions → New repository secret",[22,1116,1117],{},"在工作流中使用：",[68,1119,1121],{"className":102,"code":1120,"language":104,"meta":74,"style":74},"env:\n  API_KEY: ${{ secrets.API_KEY }}\n",[76,1122,1123,1130],{"__ignoreMap":74},[108,1124,1125,1128],{"class":110,"line":111},[108,1126,1127],{"class":114},"env",[108,1129,140],{"class":118},[108,1131,1132,1135,1137],{"class":110,"line":126},[108,1133,1134],{"class":114},"  API_KEY",[108,1136,119],{"class":118},[108,1138,1139],{"class":122},"${{ secrets.API_KEY }}\n",[36,1141,1142],{"id":1142},"缓存依赖",[68,1144,1146],{"className":102,"code":1145,"language":104,"meta":74,"style":74},"- uses: actions\u002Fcache@v4\n  with:\n    path: ~\u002F.pnpm-store\n    key: pnpm-${{ hashFiles('pnpm-lock.yaml') }}\n    restore-keys: pnpm-\n",[76,1147,1148,1160,1167,1177,1187],{"__ignoreMap":74},[108,1149,1150,1153,1155,1157],{"class":110,"line":111},[108,1151,1152],{"class":118},"- ",[108,1154,231],{"class":114},[108,1156,119],{"class":118},[108,1158,1159],{"class":122},"actions\u002Fcache@v4\n",[108,1161,1162,1165],{"class":110,"line":126},[108,1163,1164],{"class":114},"  with",[108,1166,140],{"class":118},[108,1168,1169,1172,1174],{"class":110,"line":133},[108,1170,1171],{"class":114},"    path",[108,1173,119],{"class":118},[108,1175,1176],{"class":122},"~\u002F.pnpm-store\n",[108,1178,1179,1182,1184],{"class":110,"line":143},[108,1180,1181],{"class":114},"    key",[108,1183,119],{"class":118},[108,1185,1186],{"class":122},"pnpm-${{ hashFiles('pnpm-lock.yaml') }}\n",[108,1188,1189,1192,1194],{"class":110,"line":151},[108,1190,1191],{"class":114},"    restore-keys",[108,1193,119],{"class":118},[108,1195,1196],{"class":122},"pnpm-\n",[36,1198,1200],{"id":1199},"权限与-secrets-建议","权限与 Secrets 建议",[22,1202,1203],{},"Secrets 能不用就不用，必须用时也尽量最小化权限。",[68,1205,1207],{"className":102,"code":1206,"language":104,"meta":74,"style":74},"permissions:\n  contents: read\n",[76,1208,1209,1216],{"__ignoreMap":74},[108,1210,1211,1214],{"class":110,"line":111},[108,1212,1213],{"class":114},"permissions",[108,1215,140],{"class":118},[108,1217,1218,1221,1223],{"class":110,"line":126},[108,1219,1220],{"class":114},"  contents",[108,1222,119],{"class":118},[108,1224,1225],{"class":122},"read\n",[22,1227,1228],{},"常见经验：",[82,1230,1231,1234,1244,1254],{},[46,1232,1233],{},"纯测试工作流通常只需要只读权限",[46,1235,1236,1237,1240,1241],{},"需要发 Release、写评论、推镜像时，再按需加 ",[76,1238,1239],{},"contents: write","、",[76,1242,1243],{},"packages: write",[46,1245,1246,1247,1240,1250,1253],{},"把密钥分仓库环境管理，例如 ",[76,1248,1249],{},"preview",[76,1251,1252],{},"production","，不要所有环境共用一套",[46,1255,1256],{},"部署前先确认 Secret 名称、作用域和环境是否一致",[36,1258,1260],{"id":1259},"cloudflare-pages-场景提醒","Cloudflare Pages 场景提醒",[22,1262,1263],{},"如果你已经把仓库直接绑定到 Cloudflare Pages，那么：",[82,1265,1266,1271,1284],{},[46,1267,1268,1270],{},[76,1269,441],{}," 到指定分支后，Pages 会自动拉代码并构建部署",[46,1272,1273,1274,1240,1277,1240,1280,1283],{},"这时 GitHub Actions 更适合做 ",[76,1275,1276],{},"lint",[76,1278,1279],{},"test",[76,1281,1282],{},"build"," 预检查",[46,1285,1286,1287],{},"除非你明确需要“手动部署某个产物目录”或“多环境发布”，否则没必要再在 Actions 里额外执行一次 ",[76,1288,1289],{},"pages deploy",[22,1291,1292,1293,1297],{},"简单说：",[1294,1295,1296],"strong",{},"平台自动部署负责上线，Actions 负责兜底检查","，这通常比“双重部署源”更清晰。",[36,1299,1301],{"id":1300},"常用-actions","常用 Actions",[1303,1304,1305,1318],"table",{},[1306,1307,1308],"thead",{},[1309,1310,1311,1315],"tr",{},[1312,1313,1314],"th",{},"Action",[1312,1316,1317],{},"说明",[1319,1320,1321,1332,1342,1351,1361,1370,1380],"tbody",{},[1309,1322,1323,1329],{},[1324,1325,1326],"td",{},[76,1327,1328],{},"actions\u002Fcheckout@v4",[1324,1330,1331],{},"检出代码",[1309,1333,1334,1339],{},[1324,1335,1336],{},[76,1337,1338],{},"actions\u002Fsetup-node@v4",[1324,1340,1341],{},"安装 Node.js",[1309,1343,1344,1349],{},[1324,1345,1346],{},[76,1347,1348],{},"actions\u002Fcache@v4",[1324,1350,1142],{},[1309,1352,1353,1358],{},[1324,1354,1355],{},[76,1356,1357],{},"pnpm\u002Faction-setup@v4",[1324,1359,1360],{},"安装 pnpm",[1309,1362,1363,1368],{},[1324,1364,1365],{},[76,1366,1367],{},"docker\u002Fbuild-push-action@v6",[1324,1369,809],{},[1309,1371,1372,1377],{},[1324,1373,1374],{},[76,1375,1376],{},"cloudflare\u002Fwrangler-action@v3",[1324,1378,1379],{},"Cloudflare 部署",[1309,1381,1382,1387],{},[1324,1383,1384],{},[76,1385,1386],{},"softprops\u002Faction-gh-release@v2",[1324,1388,1389],{},"创建 Release",[36,1391,1392],{"id":1392},"常见失败排查",[416,1394,1395],{"id":1395},"依赖安装失败",[82,1397,1398,1407,1410],{},[46,1399,1400,1401,1240,1404],{},"先确认锁文件是否提交，例如 ",[76,1402,1403],{},"pnpm-lock.yaml",[76,1405,1406],{},"package-lock.json",[46,1408,1409],{},"再确认工作流里使用的包管理器是否和本地一致",[46,1411,1412],{},"Node.js 版本、pnpm 版本不一致时，也很容易出现“本地能过，CI 失败”",[416,1414,1415],{"id":1415},"构建失败但本地正常",[82,1417,1418,1421,1424],{},[46,1419,1420],{},"检查是否遗漏了环境变量",[46,1422,1423],{},"检查构建命令是否依赖本地特有文件或缓存",[46,1425,1426,1427,1430],{},"检查 Linux 大小写敏感问题，例如 ",[76,1428,1429],{},"import '.\u002FUtils'"," 与真实文件名不一致",[416,1432,1433],{"id":1433},"部署成功但线上异常",[82,1435,1436,1439,1450],{},[46,1437,1438],{},"先确认部署的到底是不是最新 commit",[46,1440,1441,1442,1240,1445,1240,1448],{},"再确认产物目录是否正确，例如 ",[76,1443,1444],{},"dist",[76,1446,1447],{},".output\u002Fpublic",[76,1449,1282],{},[46,1451,1452],{},"如果平台本身有 Git 自动部署，避免 Actions 再单独部署旧产物",[416,1454,1455],{"id":1455},"工作流重复执行",[22,1457,1458,1459,1240,1461,1463],{},"同一个仓库同时配置了 ",[76,1460,441],{},[76,1462,446],{},"、平台自动构建时，很容易出现“看起来像重复跑三次”的情况。需要提前明确：",[82,1465,1466,1469,1472],{},[46,1467,1468],{},"谁负责质量检查",[46,1470,1471],{},"谁负责真正上线",[46,1473,1474],{},"哪个分支触发预览，哪个分支触发生产部署",[36,1476,1477],{"id":1477},"延伸阅读",[82,1479,1480,1486,1492,1498],{},[46,1481,1482],{},[25,1483,1485],{"href":1484},"\u002Fdocs\u002Fgit-setup","Git 安装与配置",[46,1487,1488],{},[25,1489,1491],{"href":1490},"\u002Fdocs\u002Fdocker-setup","Docker Desktop 安装与使用",[46,1493,1494],{},[25,1495,1497],{"href":1496},"\u002Fdocs\u002Flocal-setup","本地开发环境搭建",[46,1499,1500],{},[25,1501,1503],{"href":1502},"\u002Fdocs\u002Fmonitoring-logging","监控与日志",[36,1505,1506],{"id":1506},"参考链接",[82,1508,1509,1517,1525],{},[46,1510,1511,1516],{},[25,1512,1515],{"href":1513,"rel":1514},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Factions",[29],"GitHub Actions 文档"," — 官方文档",[46,1518,1519,1524],{},[25,1520,1523],{"href":1521,"rel":1522},"https:\u002F\u002Fgithub.com\u002Fmarketplace?type=actions",[29],"Actions 市场"," — 搜索 Actions",[46,1526,1527,1532],{},[25,1528,1531],{"href":1529,"rel":1530},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Factions\u002Fusing-workflows\u002Fworkflow-syntax-for-github-actions",[29],"Workflow 语法"," — 完整语法参考",[1534,1535,1536],"style",{},"html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":74,"searchDepth":126,"depth":126,"links":1538},[1539,1540,1541,1542,1543,1549,1550,1551,1552,1553,1554,1560,1561],{"id":38,"depth":126,"text":38},{"id":63,"depth":126,"text":63},{"id":92,"depth":126,"text":92},{"id":307,"depth":126,"text":307},{"id":414,"depth":126,"text":414,"children":1544},[1545,1546,1547,1548],{"id":418,"depth":133,"text":419},{"id":621,"depth":133,"text":622},{"id":808,"depth":133,"text":809},{"id":986,"depth":133,"text":987},{"id":1110,"depth":126,"text":1111},{"id":1142,"depth":126,"text":1142},{"id":1199,"depth":126,"text":1200},{"id":1259,"depth":126,"text":1260},{"id":1300,"depth":126,"text":1301},{"id":1392,"depth":126,"text":1392,"children":1555},[1556,1557,1558,1559],{"id":1395,"depth":133,"text":1395},{"id":1415,"depth":133,"text":1415},{"id":1433,"depth":133,"text":1433},{"id":1455,"depth":133,"text":1455},{"id":1477,"depth":126,"text":1477},{"id":1506,"depth":126,"text":1506},{"path":1563,"title":1564,"description":1565,"docType":8,"resourceKind":9,"categoryId":1566,"categoryLabel":1567,"updatedAt":12,"publishedAt":12,"icon":1568},"\u002Fdocs\u002Fgithub-tips","GitHub 使用技巧","GitHub 搜索语法、快捷键、Profile README、Gist 与实用功能","dev-environment","开发环境","i-carbon-code",{"path":1570,"title":1571,"description":1572,"docType":8,"resourceKind":9,"categoryId":1573,"categoryLabel":1574,"updatedAt":12,"publishedAt":12,"icon":1575},"\u002Fdocs\u002Fgo-basics","Go 语言入门","Go 安装配置、常用命令、项目结构、并发编程与交叉编译","programming-languages","编程语言","i-carbon-application",[1577,1578,1579],"希望把零散经验整理成长期可复用工作流的人","想先建立认知，再决定是否深入实践的人","希望阅读时顺手建立自己的操作清单或收藏体系的人",[1581,1582,1583],"先浏览标题、摘要和目录，带着问题阅读会更高效","顺手记录真正对你有用的命令、链接和注意事项，避免重复搜索","如果页面里提到相关文档，尽量一起打开对照，效果通常更完整",[1585,1590,1594,1596],{"path":1586,"title":1587,"description":1588,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":1589,"publishedAt":1589,"icon":13},"\u002Fdocs\u002Fcloudflare-pages-deploy","Cloudflare Pages 部署指南","Cloudflare Pages 项目部署、自定义域名、环境变量、重定向与 Functions","2026-02-28",{"path":1591,"title":1592,"description":1593,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":1589,"publishedAt":1589,"icon":13},"\u002Fdocs\u002Fs3-storage","S3 对象存储","S3 兼容存储使用、Cloudflare R2、MinIO 自建、rclone 同步与 SDK 集成",{"path":1502,"title":1503,"description":1595,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":12,"publishedAt":12,"icon":13},"服务器监控工具、日志管理、Uptime 监控与告警配置",{"path":1597,"title":1598,"description":1599,"docType":8,"resourceKind":9,"categoryId":10,"categoryLabel":11,"updatedAt":12,"publishedAt":12,"icon":13},"\u002Fdocs\u002Fcontainer-orchestration","容器编排入门","Docker Swarm 与 Kubernetes 基础概念、常用命令与本地开发环境",1776215712979]