[{"data":1,"prerenderedAt":1167},["ShallowReactive",2],{"post-docker-compose-github-actions-cicd":3},{"id":4,"title":5,"body":6,"date":1153,"description":1154,"extension":1155,"meta":1156,"navigation":60,"path":1163,"seo":1164,"stem":1165,"__hash__":1166},"blog\u002Fblog\u002Fdocker-compose-github-actions-cicd.md","docker-compose + GitHub ActionsでE2Eテストを自動化する",{"type":7,"value":8,"toc":1138},"minimark",[9,13,22,26,31,101,105,160,163,166,573,577,583,825,836,839,842,892,895,903,907,910,1100,1103,1106,1128,1134],[10,11,12],"h2",{"id":12},"はじめに",[14,15,16,21],"p",{},[17,18,20],"a",{"href":19},"\u002Fblog\u002Fjest-nestjs-e2e-testing","前回の記事","で作成したE2Eテストを、docker-composeで実行できるようにし、GitHub Actionsで自動化します。",[10,23,25],{"id":24},"dockerfileの作成","Dockerfileの作成",[27,28,30],"h3",{"id":29},"e2eテスト実行用dockerfile","E2Eテスト実行用Dockerfile",[32,33,38],"pre",{"className":34,"code":35,"language":36,"meta":37,"style":37},"language-dockerfile shiki shiki-themes github-light github-dark","# Dockerfile.test\nFROM node:14.16.1-alpine as build-stage\n\nWORKDIR \u002Fwork\n\nCOPY . \u002Fwork\u002F\n\nRUN npm install\n\nCMD [\"npm\",\"run\",\"test:e2e\"]\n","dockerfile","",[39,40,41,49,55,62,68,73,79,84,90,95],"code",{"__ignoreMap":37},[42,43,46],"span",{"class":44,"line":45},"line",1,[42,47,48],{},"# Dockerfile.test\n",[42,50,52],{"class":44,"line":51},2,[42,53,54],{},"FROM node:14.16.1-alpine as build-stage\n",[42,56,58],{"class":44,"line":57},3,[42,59,61],{"emptyLinePlaceholder":60},true,"\n",[42,63,65],{"class":44,"line":64},4,[42,66,67],{},"WORKDIR \u002Fwork\n",[42,69,71],{"class":44,"line":70},5,[42,72,61],{"emptyLinePlaceholder":60},[42,74,76],{"class":44,"line":75},6,[42,77,78],{},"COPY . \u002Fwork\u002F\n",[42,80,82],{"class":44,"line":81},7,[42,83,61],{"emptyLinePlaceholder":60},[42,85,87],{"class":44,"line":86},8,[42,88,89],{},"RUN npm install\n",[42,91,93],{"class":44,"line":92},9,[42,94,61],{"emptyLinePlaceholder":60},[42,96,98],{"class":44,"line":97},10,[42,99,100],{},"CMD [\"npm\",\"run\",\"test:e2e\"]\n",[27,102,104],{"id":103},"マイグレーション実行用dockerfile","マイグレーション実行用Dockerfile",[32,106,108],{"className":34,"code":107,"language":36,"meta":37,"style":37},"# Dockerfile.migrate\nFROM node:14.16.1-alpine\n\nWORKDIR \u002Fwork\n\nCOPY .\u002Fsrc\u002Fdatabases \u002Fwork\u002Fsrc\u002Fdatabases\nCOPY .\u002Fpackage.json .\u002Fpackage-lock.json .\u002Formconfig.ts .\u002Ftsconfig.json \u002Fwork\u002F\n\nRUN npm install\n\nCMD [\"npm\", \"run\", \"typeorm\", \"migration:run\"]\n",[39,109,110,115,120,124,128,132,137,142,146,150,154],{"__ignoreMap":37},[42,111,112],{"class":44,"line":45},[42,113,114],{},"# Dockerfile.migrate\n",[42,116,117],{"class":44,"line":51},[42,118,119],{},"FROM node:14.16.1-alpine\n",[42,121,122],{"class":44,"line":57},[42,123,61],{"emptyLinePlaceholder":60},[42,125,126],{"class":44,"line":64},[42,127,67],{},[42,129,130],{"class":44,"line":70},[42,131,61],{"emptyLinePlaceholder":60},[42,133,134],{"class":44,"line":75},[42,135,136],{},"COPY .\u002Fsrc\u002Fdatabases \u002Fwork\u002Fsrc\u002Fdatabases\n",[42,138,139],{"class":44,"line":81},[42,140,141],{},"COPY .\u002Fpackage.json .\u002Fpackage-lock.json .\u002Formconfig.ts .\u002Ftsconfig.json \u002Fwork\u002F\n",[42,143,144],{"class":44,"line":86},[42,145,61],{"emptyLinePlaceholder":60},[42,147,148],{"class":44,"line":92},[42,149,89],{},[42,151,152],{"class":44,"line":97},[42,153,61],{"emptyLinePlaceholder":60},[42,155,157],{"class":44,"line":156},11,[42,158,159],{},"CMD [\"npm\", \"run\", \"typeorm\", \"migration:run\"]\n",[10,161,162],{"id":162},"docker-compose設定",[14,164,165],{},"E2Eテスト用のdocker-compose設定ファイルを作成します。",[32,167,171],{"className":168,"code":169,"language":170,"meta":37,"style":37},"language-yaml shiki shiki-themes github-light github-dark","# unit-test.yml\nversion: '3'\n\nservices:\n  app:\n    build:\n      context: \".\"\n      dockerfile: \"Dockerfile.test\"\n    image: app-test\n    container_name: app-test\n    ports:\n      - '3000:3000'\n    environment:\n      PORT: 3000\n      TZ: 'Asia\u002FTokyo'\n      DB_HOST: 'db'\n      DB_PORT: '3306'\n      DB_USERNAME: 'test_user'\n      DB_PASSWORD: 'test_password'\n      DB_NAME: 'test_db'\n      REDIS_HOST: 'redis'\n      REDIS_PORT: '6379'\n    depends_on:\n      - db\n      - redis\n\n  redis:\n    image: redis:5.0\n    container_name: redis_container-test\n    ports:\n      - \"6379:6379\"\n\n  db:\n    image: mysql:8.0\n    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci\n    container_name: db_container_test\n    ports:\n      - 3306:3306\n    environment:\n      TZ: 'Asia\u002FTokyo'\n      MYSQL_ROOT_PASSWORD: root_password\n      MYSQL_DATABASE: test_db\n      MYSQL_USER: test_user\n      MYSQL_PASSWORD: test_password\n","yaml",[39,172,173,179,193,197,205,212,219,229,239,249,258,265,274,282,294,305,316,327,338,349,360,371,382,390,398,406,411,419,429,439,446,454,459,467,477,488,498,505,513,520,529,540,551,562],{"__ignoreMap":37},[42,174,175],{"class":44,"line":45},[42,176,178],{"class":177},"sJ8bj","# unit-test.yml\n",[42,180,181,185,189],{"class":44,"line":51},[42,182,184],{"class":183},"s9eBZ","version",[42,186,188],{"class":187},"sVt8B",": ",[42,190,192],{"class":191},"sZZnC","'3'\n",[42,194,195],{"class":44,"line":57},[42,196,61],{"emptyLinePlaceholder":60},[42,198,199,202],{"class":44,"line":64},[42,200,201],{"class":183},"services",[42,203,204],{"class":187},":\n",[42,206,207,210],{"class":44,"line":70},[42,208,209],{"class":183},"  app",[42,211,204],{"class":187},[42,213,214,217],{"class":44,"line":75},[42,215,216],{"class":183},"    build",[42,218,204],{"class":187},[42,220,221,224,226],{"class":44,"line":81},[42,222,223],{"class":183},"      context",[42,225,188],{"class":187},[42,227,228],{"class":191},"\".\"\n",[42,230,231,234,236],{"class":44,"line":86},[42,232,233],{"class":183},"      dockerfile",[42,235,188],{"class":187},[42,237,238],{"class":191},"\"Dockerfile.test\"\n",[42,240,241,244,246],{"class":44,"line":92},[42,242,243],{"class":183},"    image",[42,245,188],{"class":187},[42,247,248],{"class":191},"app-test\n",[42,250,251,254,256],{"class":44,"line":97},[42,252,253],{"class":183},"    container_name",[42,255,188],{"class":187},[42,257,248],{"class":191},[42,259,260,263],{"class":44,"line":156},[42,261,262],{"class":183},"    ports",[42,264,204],{"class":187},[42,266,268,271],{"class":44,"line":267},12,[42,269,270],{"class":187},"      - ",[42,272,273],{"class":191},"'3000:3000'\n",[42,275,277,280],{"class":44,"line":276},13,[42,278,279],{"class":183},"    environment",[42,281,204],{"class":187},[42,283,285,288,290],{"class":44,"line":284},14,[42,286,287],{"class":183},"      PORT",[42,289,188],{"class":187},[42,291,293],{"class":292},"sj4cs","3000\n",[42,295,297,300,302],{"class":44,"line":296},15,[42,298,299],{"class":183},"      TZ",[42,301,188],{"class":187},[42,303,304],{"class":191},"'Asia\u002FTokyo'\n",[42,306,308,311,313],{"class":44,"line":307},16,[42,309,310],{"class":183},"      DB_HOST",[42,312,188],{"class":187},[42,314,315],{"class":191},"'db'\n",[42,317,319,322,324],{"class":44,"line":318},17,[42,320,321],{"class":183},"      DB_PORT",[42,323,188],{"class":187},[42,325,326],{"class":191},"'3306'\n",[42,328,330,333,335],{"class":44,"line":329},18,[42,331,332],{"class":183},"      DB_USERNAME",[42,334,188],{"class":187},[42,336,337],{"class":191},"'test_user'\n",[42,339,341,344,346],{"class":44,"line":340},19,[42,342,343],{"class":183},"      DB_PASSWORD",[42,345,188],{"class":187},[42,347,348],{"class":191},"'test_password'\n",[42,350,352,355,357],{"class":44,"line":351},20,[42,353,354],{"class":183},"      DB_NAME",[42,356,188],{"class":187},[42,358,359],{"class":191},"'test_db'\n",[42,361,363,366,368],{"class":44,"line":362},21,[42,364,365],{"class":183},"      REDIS_HOST",[42,367,188],{"class":187},[42,369,370],{"class":191},"'redis'\n",[42,372,374,377,379],{"class":44,"line":373},22,[42,375,376],{"class":183},"      REDIS_PORT",[42,378,188],{"class":187},[42,380,381],{"class":191},"'6379'\n",[42,383,385,388],{"class":44,"line":384},23,[42,386,387],{"class":183},"    depends_on",[42,389,204],{"class":187},[42,391,393,395],{"class":44,"line":392},24,[42,394,270],{"class":187},[42,396,397],{"class":191},"db\n",[42,399,401,403],{"class":44,"line":400},25,[42,402,270],{"class":187},[42,404,405],{"class":191},"redis\n",[42,407,409],{"class":44,"line":408},26,[42,410,61],{"emptyLinePlaceholder":60},[42,412,414,417],{"class":44,"line":413},27,[42,415,416],{"class":183},"  redis",[42,418,204],{"class":187},[42,420,422,424,426],{"class":44,"line":421},28,[42,423,243],{"class":183},[42,425,188],{"class":187},[42,427,428],{"class":191},"redis:5.0\n",[42,430,432,434,436],{"class":44,"line":431},29,[42,433,253],{"class":183},[42,435,188],{"class":187},[42,437,438],{"class":191},"redis_container-test\n",[42,440,442,444],{"class":44,"line":441},30,[42,443,262],{"class":183},[42,445,204],{"class":187},[42,447,449,451],{"class":44,"line":448},31,[42,450,270],{"class":187},[42,452,453],{"class":191},"\"6379:6379\"\n",[42,455,457],{"class":44,"line":456},32,[42,458,61],{"emptyLinePlaceholder":60},[42,460,462,465],{"class":44,"line":461},33,[42,463,464],{"class":183},"  db",[42,466,204],{"class":187},[42,468,470,472,474],{"class":44,"line":469},34,[42,471,243],{"class":183},[42,473,188],{"class":187},[42,475,476],{"class":191},"mysql:8.0\n",[42,478,480,483,485],{"class":44,"line":479},35,[42,481,482],{"class":183},"    command",[42,484,188],{"class":187},[42,486,487],{"class":191},"mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci\n",[42,489,491,493,495],{"class":44,"line":490},36,[42,492,253],{"class":183},[42,494,188],{"class":187},[42,496,497],{"class":191},"db_container_test\n",[42,499,501,503],{"class":44,"line":500},37,[42,502,262],{"class":183},[42,504,204],{"class":187},[42,506,508,510],{"class":44,"line":507},38,[42,509,270],{"class":187},[42,511,512],{"class":191},"3306:3306\n",[42,514,516,518],{"class":44,"line":515},39,[42,517,279],{"class":183},[42,519,204],{"class":187},[42,521,523,525,527],{"class":44,"line":522},40,[42,524,299],{"class":183},[42,526,188],{"class":187},[42,528,304],{"class":191},[42,530,532,535,537],{"class":44,"line":531},41,[42,533,534],{"class":183},"      MYSQL_ROOT_PASSWORD",[42,536,188],{"class":187},[42,538,539],{"class":191},"root_password\n",[42,541,543,546,548],{"class":44,"line":542},42,[42,544,545],{"class":183},"      MYSQL_DATABASE",[42,547,188],{"class":187},[42,549,550],{"class":191},"test_db\n",[42,552,554,557,559],{"class":44,"line":553},43,[42,555,556],{"class":183},"      MYSQL_USER",[42,558,188],{"class":187},[42,560,561],{"class":191},"test_user\n",[42,563,565,568,570],{"class":44,"line":564},44,[42,566,567],{"class":183},"      MYSQL_PASSWORD",[42,569,188],{"class":187},[42,571,572],{"class":191},"test_password\n",[10,574,576],{"id":575},"typeorm設定","TypeORM設定",[14,578,579],{},[580,581,582],"strong",{},"⚠️ 警告：以下の設定を本番環境で使用するとデータが失われる可能性があります。必ずテスト専用の設定ファイルとして分離してください。",[32,584,588],{"className":585,"code":586,"language":587,"meta":37,"style":37},"language-typescript shiki shiki-themes github-light github-dark","\u002F\u002F ormconfig.test.ts\nmodule.exports = {\n  type: 'mysql',\n  host: process.env.DB_HOST || 'localhost',\n  port: process.env.DB_PORT || '3306',\n  username: process.env.DB_USERNAME || 'test_user',\n  password: process.env.DB_PASSWORD || 'test_password',\n  database: process.env.DB_NAME || 'test_db',\n  \u002F\u002F テスト環境のみ有効化：アプリケーション起動時にスキーマを自動同期\n  synchronize: true,\n  \u002F\u002F 実行SQLをログ出力\n  logging: true,\n  entities: ['src\u002Fdomain\u002Fentities\u002F*.ts'],\n  migrations: ['src\u002Fdatabases\u002Fmigrations\u002F*.ts'],\n  seeds: ['src\u002Ftest\u002Fdatabases\u002Fseeders\u002F*.seed.{js,ts}'],\n  subscribers: ['src\u002Fsubscribers\u002F**\u002F*.ts'],\n  cli: {\n    migrationsDir: 'src\u002Fdatabases\u002Fmigrations',\n    entitiesDir: 'src\u002Fdomain\u002Fentities',\n    seedersDir: 'src\u002Fdatabases\u002Fseeders',\n    subscribersDir: 'src\u002Fsubscribers',\n  },\n}\n","typescript",[39,589,590,595,613,624,640,655,670,685,700,705,715,720,729,740,750,760,770,775,785,795,805,815,820],{"__ignoreMap":37},[42,591,592],{"class":44,"line":45},[42,593,594],{"class":177},"\u002F\u002F ormconfig.test.ts\n",[42,596,597,600,603,606,610],{"class":44,"line":51},[42,598,599],{"class":292},"module",[42,601,602],{"class":187},".",[42,604,605],{"class":292},"exports",[42,607,609],{"class":608},"szBVR"," =",[42,611,612],{"class":187}," {\n",[42,614,615,618,621],{"class":44,"line":57},[42,616,617],{"class":187},"  type: ",[42,619,620],{"class":191},"'mysql'",[42,622,623],{"class":187},",\n",[42,625,626,629,632,635,638],{"class":44,"line":64},[42,627,628],{"class":187},"  host: process.env.",[42,630,631],{"class":292},"DB_HOST",[42,633,634],{"class":608}," ||",[42,636,637],{"class":191}," 'localhost'",[42,639,623],{"class":187},[42,641,642,645,648,650,653],{"class":44,"line":70},[42,643,644],{"class":187},"  port: process.env.",[42,646,647],{"class":292},"DB_PORT",[42,649,634],{"class":608},[42,651,652],{"class":191}," '3306'",[42,654,623],{"class":187},[42,656,657,660,663,665,668],{"class":44,"line":75},[42,658,659],{"class":187},"  username: process.env.",[42,661,662],{"class":292},"DB_USERNAME",[42,664,634],{"class":608},[42,666,667],{"class":191}," 'test_user'",[42,669,623],{"class":187},[42,671,672,675,678,680,683],{"class":44,"line":81},[42,673,674],{"class":187},"  password: process.env.",[42,676,677],{"class":292},"DB_PASSWORD",[42,679,634],{"class":608},[42,681,682],{"class":191}," 'test_password'",[42,684,623],{"class":187},[42,686,687,690,693,695,698],{"class":44,"line":86},[42,688,689],{"class":187},"  database: process.env.",[42,691,692],{"class":292},"DB_NAME",[42,694,634],{"class":608},[42,696,697],{"class":191}," 'test_db'",[42,699,623],{"class":187},[42,701,702],{"class":44,"line":92},[42,703,704],{"class":177},"  \u002F\u002F テスト環境のみ有効化：アプリケーション起動時にスキーマを自動同期\n",[42,706,707,710,713],{"class":44,"line":97},[42,708,709],{"class":187},"  synchronize: ",[42,711,712],{"class":292},"true",[42,714,623],{"class":187},[42,716,717],{"class":44,"line":156},[42,718,719],{"class":177},"  \u002F\u002F 実行SQLをログ出力\n",[42,721,722,725,727],{"class":44,"line":267},[42,723,724],{"class":187},"  logging: ",[42,726,712],{"class":292},[42,728,623],{"class":187},[42,730,731,734,737],{"class":44,"line":276},[42,732,733],{"class":187},"  entities: [",[42,735,736],{"class":191},"'src\u002Fdomain\u002Fentities\u002F*.ts'",[42,738,739],{"class":187},"],\n",[42,741,742,745,748],{"class":44,"line":284},[42,743,744],{"class":187},"  migrations: [",[42,746,747],{"class":191},"'src\u002Fdatabases\u002Fmigrations\u002F*.ts'",[42,749,739],{"class":187},[42,751,752,755,758],{"class":44,"line":296},[42,753,754],{"class":187},"  seeds: [",[42,756,757],{"class":191},"'src\u002Ftest\u002Fdatabases\u002Fseeders\u002F*.seed.{js,ts}'",[42,759,739],{"class":187},[42,761,762,765,768],{"class":44,"line":307},[42,763,764],{"class":187},"  subscribers: [",[42,766,767],{"class":191},"'src\u002Fsubscribers\u002F**\u002F*.ts'",[42,769,739],{"class":187},[42,771,772],{"class":44,"line":318},[42,773,774],{"class":187},"  cli: {\n",[42,776,777,780,783],{"class":44,"line":329},[42,778,779],{"class":187},"    migrationsDir: ",[42,781,782],{"class":191},"'src\u002Fdatabases\u002Fmigrations'",[42,784,623],{"class":187},[42,786,787,790,793],{"class":44,"line":340},[42,788,789],{"class":187},"    entitiesDir: ",[42,791,792],{"class":191},"'src\u002Fdomain\u002Fentities'",[42,794,623],{"class":187},[42,796,797,800,803],{"class":44,"line":351},[42,798,799],{"class":187},"    seedersDir: ",[42,801,802],{"class":191},"'src\u002Fdatabases\u002Fseeders'",[42,804,623],{"class":187},[42,806,807,810,813],{"class":44,"line":362},[42,808,809],{"class":187},"    subscribersDir: ",[42,811,812],{"class":191},"'src\u002Fsubscribers'",[42,814,623],{"class":187},[42,816,817],{"class":44,"line":373},[42,818,819],{"class":187},"  },\n",[42,821,822],{"class":44,"line":384},[42,823,824],{"class":187},"}\n",[14,826,827,828,831,832,835],{},"TypeORMの",[39,829,830],{},"synchronize: true","は、Entity定義からテーブルを自動生成する便利な機能ですが、",[580,833,834],{},"本番環境では絶対に使用しないでください","。既存のテーブル構造が上書きされ、データ損失のリスクがあります。",[10,837,838],{"id":838},"テスト実行",[27,840,841],{"id":841},"ローカルでの実行",[32,843,847],{"className":844,"code":845,"language":846,"meta":37,"style":37},"language-bash shiki shiki-themes github-light github-dark","# コンテナをビルド\ndocker-compose -f unit-test.yml build\n\n# テストを実行（テスト終了後、コンテナを自動停止）\ndocker-compose -f unit-test.yml up --abort-on-container-exit\n","bash",[39,848,849,854,869,873,878],{"__ignoreMap":37},[42,850,851],{"class":44,"line":45},[42,852,853],{"class":177},"# コンテナをビルド\n",[42,855,856,860,863,866],{"class":44,"line":51},[42,857,859],{"class":858},"sScJk","docker-compose",[42,861,862],{"class":292}," -f",[42,864,865],{"class":191}," unit-test.yml",[42,867,868],{"class":191}," build\n",[42,870,871],{"class":44,"line":57},[42,872,61],{"emptyLinePlaceholder":60},[42,874,875],{"class":44,"line":64},[42,876,877],{"class":177},"# テストを実行（テスト終了後、コンテナを自動停止）\n",[42,879,880,882,884,886,889],{"class":44,"line":70},[42,881,859],{"class":858},[42,883,862],{"class":292},[42,885,865],{"class":191},[42,887,888],{"class":191}," up",[42,890,891],{"class":292}," --abort-on-container-exit\n",[27,893,894],{"id":894},"実行結果例",[32,896,901],{"className":897,"code":899,"language":900},[898],"language-text","Recreating redis_container ... done\nRecreating db_container    ... done\nRecreating app-test ... done\nAttaching to redis_container-test, db_container_test, app-test\n\napp-test |\napp-test | > sample@0.0.1 test:e2e \u002Fwork\napp-test | > jest --config .\u002Fsrc\u002Ftest\u002Fe2e\u002Fjest-e2e.json\napp-test |\napp-test | PASS src\u002Ftest\u002Fe2e\u002Fcontractor-reps.e2e-spec.ts (92.288 s)\napp-test   契約担当者(E2E)\napp-test     ログインしていない場合は401が返ります\napp-test       ✓ OK \u002Fcontractor-reps (GET) (1471 ms)\n...\n\napp-test Test Suites: 1 passed, 1 total\napp-test Tests:       38 passed, 38 total\napp-test Time:        92.428 s\napp-test exited with code 0\n","text",[39,902,899],{"__ignoreMap":37},[10,904,906],{"id":905},"github-actions設定","GitHub Actions設定",[14,908,909],{},"プルリクエストのたびに自動でテストを実行するワークフローを設定します。",[32,911,913],{"className":168,"code":912,"language":170,"meta":37,"style":37},"# .github\u002Fworkflows\u002Ftest.yml\nname: E2E Tests\n\non:\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n  run-test:\n    name: Run E2E Tests\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout code\n        uses: actions\u002Fcheckout@v2\n        with:\n          ref: ${{ github.event.pull_request.head.sha }}\n\n      - name: Run tests with docker-compose\n        run: |\n          docker-compose -f .\u002Funit-test.yml build\n          docker-compose -f .\u002Funit-test.yml up --abort-on-container-exit\n        working-directory: .\u002F\n",[39,914,915,920,930,934,941,948,968,972,979,986,996,1006,1010,1017,1028,1038,1045,1055,1059,1070,1080,1085,1090],{"__ignoreMap":37},[42,916,917],{"class":44,"line":45},[42,918,919],{"class":177},"# .github\u002Fworkflows\u002Ftest.yml\n",[42,921,922,925,927],{"class":44,"line":51},[42,923,924],{"class":183},"name",[42,926,188],{"class":187},[42,928,929],{"class":191},"E2E Tests\n",[42,931,932],{"class":44,"line":57},[42,933,61],{"emptyLinePlaceholder":60},[42,935,936,939],{"class":44,"line":64},[42,937,938],{"class":292},"on",[42,940,204],{"class":187},[42,942,943,946],{"class":44,"line":70},[42,944,945],{"class":183},"  pull_request",[42,947,204],{"class":187},[42,949,950,953,956,959,962,965],{"class":44,"line":75},[42,951,952],{"class":183},"    types",[42,954,955],{"class":187},": [",[42,957,958],{"class":191},"opened",[42,960,961],{"class":187},", ",[42,963,964],{"class":191},"synchronize",[42,966,967],{"class":187},"]\n",[42,969,970],{"class":44,"line":81},[42,971,61],{"emptyLinePlaceholder":60},[42,973,974,977],{"class":44,"line":86},[42,975,976],{"class":183},"jobs",[42,978,204],{"class":187},[42,980,981,984],{"class":44,"line":92},[42,982,983],{"class":183},"  run-test",[42,985,204],{"class":187},[42,987,988,991,993],{"class":44,"line":97},[42,989,990],{"class":183},"    name",[42,992,188],{"class":187},[42,994,995],{"class":191},"Run E2E Tests\n",[42,997,998,1001,1003],{"class":44,"line":156},[42,999,1000],{"class":183},"    runs-on",[42,1002,188],{"class":187},[42,1004,1005],{"class":191},"ubuntu-latest\n",[42,1007,1008],{"class":44,"line":267},[42,1009,61],{"emptyLinePlaceholder":60},[42,1011,1012,1015],{"class":44,"line":276},[42,1013,1014],{"class":183},"    steps",[42,1016,204],{"class":187},[42,1018,1019,1021,1023,1025],{"class":44,"line":284},[42,1020,270],{"class":187},[42,1022,924],{"class":183},[42,1024,188],{"class":187},[42,1026,1027],{"class":191},"Checkout code\n",[42,1029,1030,1033,1035],{"class":44,"line":296},[42,1031,1032],{"class":183},"        uses",[42,1034,188],{"class":187},[42,1036,1037],{"class":191},"actions\u002Fcheckout@v2\n",[42,1039,1040,1043],{"class":44,"line":307},[42,1041,1042],{"class":183},"        with",[42,1044,204],{"class":187},[42,1046,1047,1050,1052],{"class":44,"line":318},[42,1048,1049],{"class":183},"          ref",[42,1051,188],{"class":187},[42,1053,1054],{"class":191},"${{ github.event.pull_request.head.sha }}\n",[42,1056,1057],{"class":44,"line":329},[42,1058,61],{"emptyLinePlaceholder":60},[42,1060,1061,1063,1065,1067],{"class":44,"line":340},[42,1062,270],{"class":187},[42,1064,924],{"class":183},[42,1066,188],{"class":187},[42,1068,1069],{"class":191},"Run tests with docker-compose\n",[42,1071,1072,1075,1077],{"class":44,"line":351},[42,1073,1074],{"class":183},"        run",[42,1076,188],{"class":187},[42,1078,1079],{"class":608},"|\n",[42,1081,1082],{"class":44,"line":362},[42,1083,1084],{"class":191},"          docker-compose -f .\u002Funit-test.yml build\n",[42,1086,1087],{"class":44,"line":373},[42,1088,1089],{"class":191},"          docker-compose -f .\u002Funit-test.yml up --abort-on-container-exit\n",[42,1091,1092,1095,1097],{"class":44,"line":384},[42,1093,1094],{"class":183},"        working-directory",[42,1096,188],{"class":187},[42,1098,1099],{"class":191},".\u002F\n",[10,1101,1102],{"id":1102},"まとめ",[14,1104,1105],{},"docker-composeとGitHub Actionsを組み合わせることで、以下のメリットが得られます。",[1107,1108,1109,1116,1122],"ul",{},[1110,1111,1112,1115],"li",{},[580,1113,1114],{},"環境の一貫性"," 本番環境に近い構成でテストを実行",[1110,1117,1118,1121],{},[580,1119,1120],{},"自動化"," プルリクエストごとに自動テスト実行",[1110,1123,1124,1127],{},[580,1125,1126],{},"早期発見"," 統合不具合を早期に検出",[14,1129,1130,1133],{},[39,1131,1132],{},"--abort-on-container-exit","フラグを使用することで、テスト完了後にコンテナが自動停止し、CI\u002FCDパイプラインが効率的に終了します。",[1135,1136,1137],"style",{},"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}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":37,"searchDepth":51,"depth":51,"links":1139},[1140,1141,1145,1146,1147,1151,1152],{"id":12,"depth":51,"text":12},{"id":24,"depth":51,"text":25,"children":1142},[1143,1144],{"id":29,"depth":57,"text":30},{"id":103,"depth":57,"text":104},{"id":162,"depth":51,"text":162},{"id":575,"depth":51,"text":576},{"id":838,"depth":51,"text":838,"children":1148},[1149,1150],{"id":841,"depth":57,"text":841},{"id":894,"depth":57,"text":894},{"id":905,"depth":51,"text":906},{"id":1102,"depth":51,"text":1102},"2021-11-28","docker-composeとGitHub Actionsを組み合わせて、E2Eテストを自動実行するCI\u002FCD環境を構築します。TypeORMのsynchronize機能を活用したテスト環境構築の実例も紹介します。","md",{"tags":1157},[1158,1159,1160,1161,1162],"docker","githubactions","cicd","e2e","typeorm","\u002Fblog\u002Fdocker-compose-github-actions-cicd",{"title":5,"description":1154},"blog\u002Fdocker-compose-github-actions-cicd","dUcYkPYbItEkqkxqgKrQAt32_LsRkhbKAWJ8qOJAeY8",1773664054261]