ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024 18æ¥ç®ã®èšäºã§ã 1. ã¯ããã« ããã«ã¡ã¯ããããã£æ°åïŒå¹Žç®ã®SREããŒã ã«æå±ããŠããæ»å·ã§ãã AWSç°å¢ã§Terraformã䜿ã£ãCI/CDãã€ãã©ã€ã³ãæ§ç¯ããéãèªèšŒæ
å ±ã®ç®¡çã¯é¿ããŠéããªã課é¡ã§ãããããŸã§ã”AWS Access Keyæ¹åŒ”ã䜿çšããæ¹æ³ãäžè¬çã§ããããã»ãã¥ãªãã£ãéçšã®é¢ãããæè¿ã§ã¯IAMããŒã«ã掻çšããæ¹æ³ã泚ç®ãããŠããŸãã ãã®èšäºããèŠ§ã®æ¹ã¯ãã¢ã¯ã»ã¹ããŒæ¹åŒã§ã¯ãªãIAMããŒã«ãçšããŠèªèšŒãè¡ãããæ¹ããããã¯ä»¥äžã®ãããªãšã©ãŒã®è§£æ¶ã詊ã¿ãŠããæ¹ã
ã ãšæããŸãã Error: Credentials could not be loaded, please check your action inputs: Could not load credentials from any providers ãã®ãšã©ãŒã¯GitHub ActionsãAWSãªãœãŒã¹ã«ã¢ã¯ã»ã¹ããããã®é©åãªèªèšŒæ
å ±ãèŠã€ããããªãç¶æ³ã瀺ããŠããŸãã äžèšã®èª²é¡ã¯IAMããŒã«ãçšããèªèšŒæ¹æ³ã®å®è£
ããããšã§è§£æ±ºãããšæããŸããæé ã詳现ã«èª¬æããŠããã®ã§ãã²æåŸãŸã§ãèªã¿ãã ããã 2. åŸæ¥ã®èªèšŒæ¹æ³: AWS Access Keyã®äœ¿çš 1. ä»çµã¿ AWS Access Keyã¯ãAWSã¢ã«ãŠã³ãã®ã¢ã¯ã»ã¹èš±å¯ãèšå®ããããã®ããŒã§ãã Access Key ID ãš Secret Access Key ãGitHub Secretsã«ç»é²ããGitHub Actionsã§ç°å¢å€æ°ãšããŠäœ¿çšããŸãã 以äžã¯å
žåçãªGitHub Actionsã®èšå®äŸã§ãã - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v2 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ap-northeast-1 GitHub Secretsã«ã¯ä»¥äžãä¿åããŸãã AWS_ACCESS_KEY_ID : IAMãŠãŒã¶ãŒã§äœæããAccess Key ID AWS_SECRET_ACCESS_KEY :IAMãŠãŒã¶ãŒã§äœæããSecrets Access Key 2. èª²é¡ ã»ãã¥ãªãã£ãªã¹ã¯ é·æçã«æå¹ãªã¯ã¬ãã³ã·ã£ã«ã§ãããããæµåºããå Žåã®ãªã¹ã¯ã倧ããã äžåºŠæµåºãããšãåãæ¶ããŸã§æªçšãããå¯èœæ§ãããã æš©éã®å¶åŸ¡ãé£ãã IAMãŠãŒã¶ãŒåäœã§ã®æš©éä»äžã«ãªããããCI/CDå°çšã®çްããªæš©éèšå®ãé£ããã å¿
èŠä»¥äžã®æš©éãä»äžããããããæå°æš©éã®ååã«åããå¯èœæ§ãããã 3. æ°ããèªèšŒæ¹æ³: IAMããŒã«ãšGitHub Secrets 1. ä»çµã¿ AWSã®IAMããŒã«ã䜿ãã°ãé·æçãªã¢ã¯ã»ã¹ããŒã䜿ããã«å®å
šã«èªèšŒãè¡ããŸããGitHub ActionsãAWSã«äžæçãªæš©éããªã¯ãšã¹ãããããšã§ãæå°éã®æš©éã§æäœãè¡ããŸãã 以äžã®ããã«èšå®ããŸãã - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v2 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} aws-region: ap-northeast-1 GitHub Secretsã«ã¯ä»¥äžãä¿åããŸãã AWS_ROLE_ARN : äœæããIAMããŒã«ã®ARN 3.2 ã¡ãªãã ã»ãã¥ãªãã£åäž GitHub Actionsã§ã®ã¿æå¹ãªäžæçãªæš©éã䜿çšãããããã¯ã¬ãã³ã·ã£ã«æµåºã®ãªã¹ã¯ãäœæžã äžæçãªèªèšŒæ
å ±ã¯çæéã§å€±å¹ãããããäžãäžæµåºããŠã圱é¿ãæå°éã«æããããã æå°æš©éã®é©çšã容æ IAMããŒã«ã«å¯ŸããŠå¿
èŠæå°éã®æš©éãèšå®å¯èœã Assume Roleã䜿çšããããšã§ãç¹å®ã®ãªãœãŒã¹ããµãŒãã¹ã«å¯Ÿããæš©éã现ããå¶åŸ¡ã§ããã CI/CDåŠçã«å¿
èŠãªæäœã®ã¿ãèš±å¯ããIAMããªã·ãŒãæè»ã«èšå®å¯èœã 4. æ¯èŒ: AWS Access Key ãš IAMããŒã« é
ç® AWS Access Key IAMããŒã« éçšè² è· é«ã äœã 远跡 é£ãã å®¹æ æå°æš©éã®é©çš é£ãã 容æ 5. å®è£
æé Step 1: IAM OIDC IDãããã€ãã远å OpenID Connectãéžæ ãããã€ãã®URLã« https://token.actions.githubusercontent.com 察象è
ã« sts.amazonaws.com ãããã€ãã远å ãã¯ãªã㯠Step 2: IAMããŒã«ãäœæ AWS CLIãŸãã¯AWSã³ã³ãœãŒã«ã§IAMããŒã«ãäœæããŸãã以äžã®èšå®ãè¡ããŸãã IAMããŒã«ã®ä¿¡é Œé¢ä¿ãèšå® ããŒã«ãä¿¡é Œãããšã³ãã£ãã£ãšããŠGitHub Actionsãæå®ããŸãã { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::xxxxx:oidc-provider/token.actions.githubusercontent.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" }, "StringLike": { "token.actions.githubusercontent.com:sub": [ "repo:xxxxx/*" ] } } } ] } ããªã·ãŒã®ã¢ã¿ãã Terraformã«å¿
èŠãªæš©éïŒäŸ: S3, EC2, IAMïŒã®ã¿ãä»äžããŸãã Step 3: GitHub Secretsã«ç»é² GitHubã®settingâActions secrets and variablesâactionsããsercretsã«ä»¥äžã®å€ãç»é² AWS_ROLE_ARN : Step2ã§äœæããIAMããŒã«ã®ARN Step 4: GitHub Actionsã®èšå® .github/workflows/terraform.yml ïŒä»»æã®ãã¡ã€ã«ïŒã§ç°å¢å€æ°ãå®çŸ©ããã äžèšã¯terraformã®CIã®å®è£
äŸ name: Terraform CI on: push: branches: - main jobs: terraform: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v2 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} - name: Setup Terraform uses: hashicorp/setup-terraform@v2 with: terraform_version: 1.9.8 - name: Terraform Init run: terraform init - name: Terraform Plan run: terraform plan 6. ãŸãšã åŸæ¥ã®AWS Access KeyãçšããèªèšŒæ¹æ³ã«ã¯ãã»ãã¥ãªãã£ãšéçšã®èª²é¡ããããŸããããIAMããŒã«ã掻çšããããšã§ãèªèšŒæ
å ±ã容æã§ã»ãã¥ã¢ã«èšå®ããããšãã§ããŸãïŒ ãã²ããã®æ¹æ³ã詊ããŠã¿ãŠãã ããïŒ
ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024 19æ¥ç®ã®èšäºã§ãã ã¯ããã« ãã¯ããããããŸããIWSã§ãã å°ããããªãã«ã¯ãªãã®ã§ãããã¿ãªããã¯ããã ããã¯å¥œãã§ããïŒå¥œãã§ãããïŒ åã
ããã²ãŒã 宿³ã®åç»ãªã©ã§æŽ»èºããŠãããããCevio AI Songã ã ãNEUTRINOã ãªã©ãåºãŠæãããã ãããããããšèŠãããæ©äŒãå€ããªã£ãã®ã§ã¯ãªãããšæããŸãã ç§ã ãVOICEPEAK æ±åããããã ã賌å
¥ããŠäžç·ã«ã€ããŠãã ããã ãã ãåãããŠéãã ãããŸããã ã§ãããåãããŠçµããã§ã¯å°ãå¯ããããç§ãããã ããã§ãªã«ãããããªãããšæã£ãã®ã§ã¡ãã£ãšãã£ãŠã¿ãŸããã ããããããš ãããã£ã«ã¯ãããããã ãšããããã¹ããæçš¿ãããšé³å£°ã«å€æããŠã³ãã¥ãã±ãŒã·ã§ã³ãåãã瀟å
Webã¢ããªããããŸããïŒããããã«ã€ããŠã¯ãã² ãã¡ãã®ããã° ãã芧ãã ããïŒ é³å£°ã¯ Amazon Polly ã䜿ã£ãŠçæããŠããã®ã§ãããããã«ã¿ããªã倧奜ã㪠ããã ãã ã远å ããããšããã®ãç®æšã§ãã ã€ã¡ãŒãžãšããŠã¯ãããªæãã§ãããã ããããã Node.js ã§äœãããŠããã®ã§ãã¡ããããã«åãããŸãã ã¯ã©ã€ã¢ã³ãåŽããããã¹ããéä¿¡ããŠããããµãŒããŒåŽãžæž¡ãããµãŒããŒåŽã¯ãããVOICEVOXã®ã³ã³ãããžããã«ãªã¯ãšã¹ããé£ã°ããŠé³å£°ããŒã¿ãçæããŠããããšãã圢ã§ãã VOICEVOX åãããã ããã«ã¯ãCevio AIãããVOICEPEAKããªã©ãããŸããä»åã¯APIã§å©çšããããšããã®ãããã®ã§ãVOICEVOXãã䜿çšããŸãã https://voicevox.hiroshiba.jp/ core , engine , editor ã®3çš®é¡ããããŸããAPIãšããŠåŒã³åºããŠé³å£°åæãã§ããã°ããã®ã§ VOICEVOX_engine ãéžãã§ããŸãã https://github.com/VOICEVOX/voicevox/blob/main/docs/å
šäœæ§æ.md Docker Hubã§ã€ã¡ãŒãžãå
¬éãããŠããã®ããããããã§ãã https://hub.docker.com/r/voicevox/voicevox_engine docker-compose.yml ã«ããã远å ããã ãã§ã³ã³ãããç«ã¡äžããããŸã voicevox: image: voicevox/voicevox_engine:0.20.0 container_name: voicevox ports: - '50021:50021' ããã ãããã€ã¹ãçæããã VOICEVOXã®APIã«ãªã¯ãšã¹ããæããããšã§é³å£°ãçæããããšãã§ããŸãã APIã«ã¯ãããã¹ããé³å£°ã¯ãšãªã«å€æããAPIããšãé³å£°ã¯ãšãªãé³å£°ããŒã¿ã«å€æããAPIãã®2çš®é¡ãããã2ã€ã®APIãããããåŒã¶ããšã§ããã¹ãããé³å£°ããŒã¿ã®çæãŸã§ãè¡ããŸã https://github.com/VOICEVOX/voicevox_engine?tab=readme-ov-file#http-ãªã¯ãšã¹ãã§é³å£°åæãããµã³ãã«ã³ãŒã // ããã¹ãããé³å£°ã¯ãšãªãäœæ const query = axios.create({ baseURL: `http://voicevox:50021`, responseType: 'json', }); const queryResponse = await query .post(`/audio_query?text=${text}&speaker=3`) .catch((error) => { console.error(error); }); if (!queryResponse) { return ''; } // é³å£°ã¯ãšãªããé³å£°ãåæ const synthesis = axios.create({ baseURL: `http://voicevox:50021`, headers: { 'Content-Type': 'application/json', }, responseType: 'arraybuffer', }); const jsonString = JSON.stringify(queryResponse.data); const synthesisResponse = await synthesis .post(`/synthesis?speaker=3`, jsonString) .catch((error) => { console.error(error); }); if (!synthesisResponse) { console.log('é³å£°ã®åæã«å€±æããŸãã'); return ''; } APIãåŒã¶éã«ã¯ãšãªãã©ã¡ãŒã¿ãŒã§ speaker={id} ãšããããšã§é³å£°ã©ã€ãã©ãªã®å¥œããªãã£ã©ã¯ã¿ãŒã«åãããããšãã§ããŸãã3 ã§ããã ããã8 ã§ æ¥æ¥éšã€ãã ã«åã£ãŠãããããšãã§ããäžéšãã£ã©ã¯åãæ¹ãå€ããããã§ããŸããïŒã»ã¯ã·ãŒããã ããã«ãããããããããã ããã«ãããâŠâŠïŒ é³å£°ã©ã€ãã©ãªã®äžèЧã¯ã³ã³ãããç«ã¡äžã㊠/speakers ã«ã¢ã¯ã»ã¹ãããšèŠãããšãã§ããŸãã é³å£°åæãã§ããããã¡ã€ã«ã«ä¿åããŠãããŸãã // äžæã®ããŒã¯ã³ãçæ const token = uuidv4(); // Pathã®æå®ãšé³å£°ãã¡ã€ã«ã®ä¿å const audioPath = path.join( process.cwd(), 'public', 'audio', `${token}.mp3` ); fs.writeFileSync( audioPath, new Uint8Array(synthesisResponse.data as Buffer) ); const speakUrl = `/audio/${token}.mp3`; return speakUrl; ããŒã¯ã³ãã€ãã£ãŠé©åœãªååã§ä¿åããŠããã ãã§ãããã¡ã€ã«ã®ä¿åãã§ããããã®ãã¡ã€ã«ãžã®Pathãè¿ããŠããŸãã Pathãè¿ããŠããã®ã¯ã¯ã©ã€ã¢ã³ãåŽã§ /audio/${token}.mp3 ãåçãããšããå®è£
ãããŠããããã§ããè¿ã£ãŠãã speakUrl ã®URLã䜿çšã㊠const music = new Audio(speakUrl); music.play(); ã®ããã«ããŠãããã°ãã©ãŠã¶åŽã§é³å£°ãåçãã§ããŸãã ã³ãŒãå
šäœ // VOICEVOX export const voicevoxTextToSpeakUrl = async (text: string): Promise<string> => { /** * ããã¹ããVOICEVOXã§é³å£°ã«å€æãé³å£°ãã¡ã€ã«ã®URLãè¿ããŸãã * * @param text é³å£°ã«å€æããããã¹ã * @returns é³å£°ãã¡ã€ã«ã®URLã倱æããå Žåã¯ç©ºæåå */ try { // é³å£°ã¯ãšãªãäœæ const query = axios.create({ baseURL: `http://voicevox:50021`, responseType: 'json', }); const queryResponse = await query .post(`/audio_query?text=${text}&speaker=3`) .catch((error) => { console.error(error); }); if (!queryResponse) { return ''; } // ã¯ãšãªããé³å£°åæ const synthesis = axios.create({ baseURL: `http://voicevox:50021`, headers: { 'Content-Type': 'application/json', }, responseType: 'arraybuffer', }); const jsonString = JSON.stringify(queryResponse.data); const synthesisResponse = await synthesis .post(`/synthesis?speaker=3`, jsonString) .catch((error) => { console.error(error); }); if (!synthesisResponse) { console.log('é³å£°ã®åæã«å€±æããŸãã'); return ''; } // äžæã®ããŒã¯ã³ãçæ const token = uuidv4(); // Pathã®æå®ãšé³å£°ãã¡ã€ã«ã®ä¿å const audioPath = path.join( process.cwd(), 'public', 'audio', `${token}.mp3` ); fs.writeFileSync( audioPath, new Uint8Array(synthesisResponse.data as Buffer) ); const speakUrl = `/audio/${token}.mp3`; // äžåºŠåçãããé³å£°ãã¡ã€ã«ã¯ãã䜿ããªãããåé€ setTimeout(() => { fs.unlink(audioPath, (err) => { if (err) { console.error(`ãã¡ã€ã«åé€ãšã©ãŒ: ${audioPath}`, err); } else { console.log(`ãã¡ã€ã«ãåé€ãããŸãã: ${audioPath}`); } }); }, 20000); return speakUrl; } catch (e) { console.error('error: ', e); return ''; } }; ãŸãšã VOICEVOXãã€ãã£ãŠããã ãããè§Šã£ãŠã¿ãŸãããAPIãæäŸãããŠãããããã§ããããã«ç°¡åã«ããã ãããçµã¿èŸŒãããšãã§ããŸããããããã§ããã ããã©ã€ããå
å®ããŸãïŒ ãã²çãããVOICEVOXã䜿ã£ãŠãªã«ããã£ãŠã¿ãŠãã ããïŒ ææ¥ã¯ @takatakanian ããã®èšäºã§ãïŒã楜ãã¿ã«ïŒ ã¯ã¬ãžãã VOICEVOX:ããã ãã
ãšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒãããŠããŸãèŠå·ã§ãã2024幎12æ16æ¥ã« GitHub Universe 2024 Recap in ZOZO ã«åå ãç»å£ãããŠããã ããŸããã®ã§ããã®ãå ±åããããŸãã ã€ãã³ãå
容ãšããŠã¯ãåé ãGitHub æéšæ§ã«ãã GitHub Universe 2024 ã®RecapïŒãã¡ããã¡ãäžå¯§ãªèª¬æãcopilotåå¿è
ã®ç§ã§ãåããå
容ïŒïŒãç¶ããŠæ ªåŒäŒç€ŸZOZO å±±ç°æ§ã«ããiOSéçºã«ãããCopilot For XcodeãšCode CompletionïŒ3çªåè² ãéåžžã«é¢çœãã£ãã§ãïŒcopilotã®åã¡ïŒïŒãå瀟äœè€æ§ã«ããGitHub Copilot ã®ãã¯ããã¯éïŒããã«ã§ã䜿ããã·ã§ãŒãã«ãããããã³ããã®æžãæ¹æºèŒã§ããïŒïŒãšãããšããã§ãçæéãªãããéåžžã«æ¿å¯ãªæéã§ããã ç§ã®æ¹ããã¯ãGitHubã®æŽ»çšäºäŸãšããŠãã€ã³ããŒãœãŒã¹ã®åãçµã¿ãã¡ã€ã³ã«è©±ãããŠããã ããŸãããAsk the speakerã®æéã§ã¯ããå¶ç¶ã仿¥ã瀟å
ã§ã€ã³ããŒãœãŒã¹éšãç«ã¡äžããŠã€ã³ããŒãœãŒã¹ãå§ãããšããã§ãïŒããšããæ¹ãããŸããŠãç¥ã®åãäœãã§åŒãåãããŠãããã®ããªããšããããããåŒåãæã£ãå Žã§ãããææçŸ©ãªæéãéããããšãã§ããŸãããããããšãããããŸãã ã¹ã©ã€ãå
šäœã¯ãã¡ãã«ãªããŸãã ã©ããªäŒç€ŸïŒãšã³ãžãã¢çµç¹ã®æ§é ïŒGitHubå°å
¥ç¶æ³ïŒ ããããã¯ãã¹ã©ã€ããããã¯ã¢ããããŠããã話ããå
容ãæç« ã«ããŠããããšæããŸãã ã³ã©ãã¬ãŒã·ã§ã³æåã®è©±ãããã®ã§ããŸãäŒç€Ÿã®çµç¹æ§é ã«ã€ããŠã話ããŸãããå®éã®è·å¶ãšã¯ç°ãªããŸãããããŒã ããããžãŒã®ããŒã ã¿ã€ãã«ããããšãã£ãããã®ãããªãšã³ãžãã¢çµç¹ã®æ§é ã«ãªããŸãããšã³ãžãã¢ã¯å
šéšã§çŽ160åããŸããŠã7-10åã»ã©ã®ãµãããŒã ã«ããããŠãããŸããŠãå
補éçºãã¡ã€ã³ã§ãã æ³šç®ãããšãããšããŠã¯ãã¹ããªãŒã ã¢ã©ã€ã³ãããã¡ã€ã³ã®éãã§ãã£ãã2åå²ãããŠããç¹ã ã£ãããããšã¯ãã³ã³ããªã±ã€ããããµãã·ã¹ãã ã§ã¯ãISPç¬èªã®ãããã¯ãŒã¯éšåãæ±ã£ãŠãããããªãšããã§ããããïŒ æ¬¡ã«GitHubå©çšç¶æ³ã§ããorganizationã¯1ã€ã§ãããRepository creationã«ãŒã«ã¯ãinternalãšããŠããŠãçµç¹å
ã®èª°ã§ããªããžããªé²èЧå¯èœãããã©ã«ãã«ããŠããŸããäžæ¹ãCopilot Metrics Viewerããã¿ãcopilotã®å©çšç¶æ³ã§ãããã¡ãã®å°å
¥ã¯å
šå¡ã§ã¯ãŸã ãããŸããããã³ãŒãåãå
¥ãçã¯31%ã§ãããå²ãšããæããªã®ããªããšæã£ãŠãããŸããèšèªã¯pythonããšãã£ã¿ã¯vscodeãå€ãã§ããã ããããã€ã³ããŒãœãŒã¹ã®è©± ããããã€ã³ããŒãœãŒã¹ã®è©±ã§ãã 2022幎ã®äžæã ã£ããšããããŸãããç§å«ããåšèŸºã®ãããŒãžã£ãŒã®äžã§ããæ©ã¿ããããŸãããäºæ¥éšããã¯ãã£ãšããããããšããèŠæã¯ããããã§ãã®ã§ãããéçºãªãœãŒã¹ãéãããŠãããå€éšçºæ³šããããŸãããã§ãããã£ãã·ã¥ã¢ãŠãããã«ãã£ãšå
éšã§ããŸãåããããæ¹ãç¹å®ã®ããŒã ãžéçºäŸé ŒãéäžããŠããŸããããªç¶æ³ãæéãããã®ã¯ãªãããšãã§ãããããã°ã°ã£ãã®ã§ãããããã¯è¡æçãªåºäŒãã§ããããã®äžã®äžã«ã¯ãã€ã³ããŒãœãŒã¹ããšããããæ¹ãããããšãç¥ããŸããã æåã«ç§ãèªãã ã®ã¯ãå³ã®codezineã«ä¹ã£ãŠãããšããæ±èã®å°æãããæžããèšäºã ãªãŒãã³ãœãŒã¹ã®éçºã¹ã¿ã€ã«ãäŒæ¥å
ã§å®è·µããã€ã³ããŒãœãŒã¹ãšã¯ïŒ ã¡ãªãããšãã€ã³ããçè§£ãã ãã§ãããã®ãããããããããã£ãã§ããã§ãããå°å
¥ãããäœåã®ãã人ãã»ãã®ããŒã ã®éçºæäŒããããã«ãªãã®ã§ã¯ïŒãšå®æã«æããŸããŠãçµç¹ã«ãã€ã³ããŒãœãŒã¹ããšãããå°å
¥ããããšåŒ·ãæã£ãããã§ãã ã§ãããããšããå§ããŸããããã®ãããã®ãã ãã¯ã以äžã®èšäºã®ã»ãã詳ããã§ãã®ã§å²æããŸããããªããªãããŸããããŠããã®ã§ã¯ïŒãšæã£ãŠããŸãã ã€ã³ããŒãœãŒã¹ãå°å
¥ããŠã¿ã ãã®â ã詊ãå°å
¥ç·š ã€ã³ããŒãœãŒã¹ãå°å
¥ããŠã¿ã ãã®â¡ åå°äœãç·š ãŸããä»åã®çºè¡šã§ã¯ãçµç¹ã«ããããæ°ããæµããããããšãã«ãšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒãšããŠã©ã®ããã«åãããã«ã€ããŠæ°ããè§ŠããŸãããçã
ãã話ã«ã¯ãªããŸãããç§ãšããŠã¯ã以äžã®ãããªããšãããŠããŸããã ãããããŠã³ã§é²ãã§ããããã«ã¯èŠãããããªããŠã1人çŸå Žã¡ã³ããŒã®æšé²è
ãæ±ºãããã®ã¡ã³ããŒããå
šç€Ÿãžçºä¿¡ããããã«ä»åããããš åšãã®ãããŒãžã£ãŒãå·»ã蟌ã¿ãäºæ¥èšç»ãšããŠã€ã³ããŒãœãŒã¹æšé²æŽ»åãå
¬åŒåããããš ã€ã³ããŒãœãŒã¹ã¬ã€ãã©ã€ã³ã§ã¯ãã³ã³ããªãã¥ãŒã¿ãŒã®è©äŸ¡ãå·¥æ°ã®èãæ¹ãå«ããããš æ¥åã®äžç°ãšããŠã€ã³ããŒãœãŒã¹ã³ãã¥ããã£éå¶ã«æºãããããã«ããããš ãã®ããããããŸããã£ãã®ããªãããšèããŠããŸããããå°ãã现ããè©±ãæžããããªã®ã§ããã€ããæ°ããåãçµã¿ãããã ã¢ããã§çµç¹ã«å°å
¥ããã«ã¯ïŒãã¿ããã«æœè±¡åãããé¡ã§æžããŠã¿ãããšæããŸãã ã€ã³ããŒãœãŒã¹ãããŸããã£ãŠãããšãã å人ã§äœã£ãããŒã«ãžã®ã³ã³ããªãã¥ãŒãããæ¥åã«å°ãèžã¿èŸŒãã ãšããã ãšãAPIå©çšè
å®çŸ©ãã¡ã€ã«ã®è¿œå ã«ã€ããŠæããã«ãªãŒãã¿ã€ã ãççž®ã§ããäºäŸãªã©ã玹ä»ããŸããããã®ãããã®è©±ã¯ãå°æŸã®äžèšã®ç»å£å
容ã§ããããŸãã®ã§ãããã§ã¯å²æããããŸãã ã€ã³ããŒãœãŒã¹ãããŸããã£ãŠããªããšãã ãã®ããã°ã§ã¯ããããŸã§ããŸãèªã£ãŠããªãã£ããããŸã®ãšããããŸããã£ãŠãªããšãããæç« åããŠãããŸãããã£ãŠã¿ãŠãããšãããããªããã¿ãŒã³ãããããšãäœæãšããŠããã£ãŠããŸãããäŸãã°ããã¡ã€ã³ç¥èãéãå士ã®ã¹ããªãŒã ã¢ã©ã€ã³ãããŒã ã®ã³ã©ãã¬ãŒã·ã§ã³ã§ãã ãã¡ã€ã³ãåãããŒã å士ã§ããã°ãããžãã¹ã®æ¹åãåãããŒã ã©ãããŠããã°ãã©ã¡ãã®ããŒã ãæäŸããŠããAPIããäºãå©çšããªãããããã«ã³ã³ããªãã¥ãŒããçãŸããäœå°ãããããšæãã®ã§ãããäŸãã°ãåŒç€Ÿã®äŸã§ãããšãWEBãµãŒãã¹ãšãISPãµãŒãã¹ã¯ããªã屿§ãéããšããããå俵ãéããšãããããã¡ã€ã³ãããªãç°ãªãããŒã ã§ãããããã«ã¯ã³ã³ããªãã¥ãŒãããããã®ã¢ãããŒã·ã§ã³ãããŸããªãã®ã§ãå³ããããªããšæ£çŽã«æã£ãŠããŸããïŒãã¡ããå人ã®ã¹ãã«ã¢ããããã£ã¬ã³ãžç²Ÿç¥ãšãããšããã¯å€§æè¿ã§ãããããŒã¹ãšããŠããšããæå³ã§ããïŒ èããŠã¿ãã°ãã³ã³ããªãã¥ãŒãã¯å·±ãå·±ã®ããŒã ã®ããã«ãŸããã£ãŠã¿ããããšæãã¯ããªã®ã§ãããããååããããŒã ã§ãªããã°ããã£ã±ãããŸããªãããªããšæã£ããšããã§ãã ã€ã¥ããŠã¯ããã¥ã¡ã³ããžã®ã³ã³ããªãã¥ãŒãã§ãããœãŒã¹ã³ãŒãã«PRãåºãããã¯å§åçã«ããã¥ã¡ã³ãã«PRãåºãã»ããããŒãã«ã¯äœããšæããŸããããåŒç€Ÿã§ã¯ããã¹ãŠã®ããã¥ã¡ã³ãããªããžããªã§ç®¡çãããŠã¯ãªããã©ããããé²ããŠããããããšçŸåšæ©ãã§ãããšããã§ããã©ãªããå©ããŠãã ãããããããããŠãçæAIã§ããããªããã¹ãåãã§ãããšããæãã«ãªãã®ã§ããããïŒ ããã¯çšèªã瀟å
ã«å
ã«åºãŸã£ãåãçè§£ãå®ã¯ããŸã远ãã€ããŠããªãã£ãïŒãšããæ³åã§ããæ°èŠãããã¯ãéçºãããªã«ãã®äºæ
ããããã©ãã¯ããã¯ã¹ã»éçšä¿å®ã³ã¹ãå¢ã«ãªã£ãŠããŸã£ãã·ã¹ãã ã®æ¹åã«é¢ããŠãã€ã³ããŒãœãŒã¹ã¯å¯äžããŸããïŒèª€è§£ãªãããããã«ã ãŸãšã ã§ããŸãšãã«ãªããŸãã çµç¹å
ã§ã³ã©ãã¬ãŒã·ã§ã³æåãã©ãäœããããããšãããšãããã€ã³ããŒãœãŒã¹ã«ãã£ã¬ã³ãžããŠèŠããŠããŸããã ãŸããåå°ãšãªããã©ãããã©ãŒã ãå¿
èŠã§ããã€ãŸãGitHubã§ãã æ¬¡ã«ãã³ã©ãã¬ãŒã·ã§ã³ããæ¹æ³ã®æç¢ºåãå¿
èŠã§ãã€ãŸãã€ã³ããŒãœãŒã¹ã§ãã ãã©ãããã©ãŒã ãã³ã©ãã¬ãŒã·ã§ã³æ¹æ³ã ãã§ã¯ã³ã©ãã¬ãŒã·ã§ã³ã¯çãŸããŸãããæåŸã«ã人éãå¿
èŠã§ããã 倧äºãªç¹ãšããŠåãæ¹åãåããŠããããšãã€ãŸããäºããã¡ãªããã享åã§ããéæ ã§ããå¿
èŠããããŸãã 以äžã3ç¹ãçµç¹ã®åŸãçŸïŒè©äŸ¡å¶åºŠãå·¥æ°ç®¡çãªã©äŒç€Ÿã®åãã®äžã§å
¬åŒçã«åãããããšããç¹ïŒãè¡ãããšã§éæãããã®ã§ã¯ãªããããããšããã®ãçŸæç¹ã§ã®çµè«ã«ãªããŸãã ãŸã éåã°ã§ã®éäžã®ç¶æ
ã§ããããŸã鲿ããæ¬¡ç¬¬ã¢ããããŒãããŠãããããšæããŸãïŒ ä»¥äžã§ãã
ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024 16æ¥ç®ã®èšäºã§ãã ã¯ããã« ä»æã¯äºæ¬ç®ã®ããã°æçš¿ãããå®®æ¬ã§ããã²ãšæã®éã«ããã°äºæ¬æžãã®ã¯ãªããªãããã©ãã§ãããäžäººã¢ããã³ãã«ã¬ã³ããŒããã£ãŠããæ¹ãšãåããšæããŸãã ä»åã¯ãReactã®ErrorBoundaryã®ãã°åºåã«ã€ããŠã§ãããªããReactåäœã§å®è£
ã§ããã¯ã©ã¹ã³ã³ããŒãã³ããå©çšãããã®ã§ã¯ãªãã颿°ã³ã³ããŒãã³ãã§å©çšã§ãã react-error-boundary ã察象ãšããŠããŸãã ãã°ãç°¡åã«åºããããããšã€ãã§ã«äœ¿ããŸãããããã«ãããã å¹³ããèšãã°Reactã³ã³ããŒãã³ãã®try-catchã®ãããªåœ¹å²ãããErrorBoundaryã§ããã宿œã§ããããšã¯çµæ§éãããŸãã ãšã©ãŒçºçæã®ä»£æ¿ã³ã³ããŒãã³ãã®è¡šç€º 代æ¿ã³ã³ããŒãã³ãå
ã§ã®ãªã»ããåŠçã®è¿œå ãšã©ãŒçºçæã«ãããããæå®ãããã°åºåçšã®é¢æ°ãå®è¡ ä»ã«ãæç€ºçã«ErrorBoundaryã®åŒã³åºãã»åã¬ã³ããªã³ã°ãã§ããhookãçšæãããŠãããããŸãããå¿çšã«ãªãããä»åã¯å²æããšããããErrorBoundaryãå
¥ãããïŒãšãªã£ãå Žåã«äœ¿ãã®ã¯ã代æ¿ã³ã³ããŒãã³ãã®è¡šç€ºãšãšã©ãŒæã®ãã°è¡šç€ºã ãšæããŸãã ããŠã代æ¿ã³ã³ããŒãã³ãã®äžèº«èªäœã¯ã¢ããªã±ãŒã·ã§ã³ã«ãããŸã¡ãŸã¡ã ãšæããŸããããšã©ãŒãã°ã®è¡šç€ºãšãªããšè¡šç€ºå
容ã¯å²ãšéãããŸãããšã©ãŒã®çš®é¡ããšã«ãšã©ãŒå
容ãå€ãããšãªããšçްããåå²ãå
¥ããå¿
èŠããããŸããããæäœéãšã©ãŒããããã°âŠâŠããšããã¬ãã«ãªãã§ããã ãæ¥œã«æžãããã§ãã ErrorBoundaryã§ãã°åºåãããäŸãšããŠãonErrorã§å®è¡ãã颿°å
ã§ãã°åºåãããæ¹æ³ãå
¬åŒã§ç޹ä»ãããŠããŸãã // https://github.com/bvaughn/react-error-boundary?tab=readme-ov-file#logging-errors-with-onerror ããäžéšä¿®æ£ "use client"; import { ErrorInfo } from 'react'; import { ErrorBoundary } from "react-error-boundary"; // 倿Žç¹ïŒinfoã®åã¯react-error-boundary 4.0ããReactã®ErrorInfoåãå©çš const logError = (error: Error, info: ErrorInfo) => { // Do something with the error, e.g. log to an external API }; const ui = ( <ErrorBoundary FallbackComponent={ErrorFallback} onError={logError}> <ExampleApplication /> </ErrorBoundary> ); ããããã®onErrorã§å®è¡ãã颿°ãåŒæ°ããããããæ±ºãŸã£ãŠãããšã©ãŒãªããžã§ã¯ããšã³ã³ããŒãã³ãã®ã¹ã¿ãã¯ããæž¡ãããŸãããäžå¿ã¹ã¿ãã¯ã¯æž¡ãããã®ã§ã©ãã§çºçãããšã©ãŒãã¯ãããããã«ãªã£ãŠããŸãããããããŠErrorBoundaryã仿ããå Žæã決ãŸã£ãŠããã®ã§ããã°ããã°äžã«äžçºã§ããšã©ãŒçºçç®æã¯ããã ïŒããšããããããªæèšãä»èŸŒã¿ããã§ãã // ãããªæãã«ErrorBoundaryããããããããšããããšã©ãŒãçºçããå Žåãã©ãã§çºçãããšã©ãŒãªã®ãåããã¥ãã const logError = (error: Error, info: { componentStack: string }) => { console.error("ãšã©ãŒçºç!", Error, componentStack) }; const uiFirst = ( <ErrorBoundary FallbackComponent={ErrorFallback} onError={logError}> <ExampleApplicationFirst /> </ErrorBoundary> ); const uiSecond = ( <ErrorBoundary FallbackComponent={ErrorFallback} onError={logError}> <ExampleApplicationSecond /> </ErrorBoundary> ); ããã§ã次ã®ããã«ãã°åºåçšã®é¢æ°ãäœæããcreateLogError颿°ãçšæããŠãcreateLogErrorã®åŒæ°ã§äžããå€ïŒlogIdïŒããã°åºåã§å©çšããããã«ããŸãã const createLogError = (logId: string) => (error: Error, info: ErrorInfo): void => { console.error(`${logId} ãšã©ãŒçºç!`, error, info.componentStack); }; const uiFirst = ( <ErrorBoundary FallbackComponent={ErrorFallback} onError={createLogError("ui-first")}> <ExampleApplicationFirst /> </ErrorBoundary> ); const uiSecond = ( <ErrorBoundary FallbackComponent={ErrorFallback} onError={createLogError("ui-second")}> <ExampleApplicationSecond /> </ErrorBoundary> ); äžèšã®äŸãå®éã«äœ¿ããšä»¥äžã®ããã«ãªããŸãã export default function Home() { return ( <ErrorBoundary FallbackComponent={FallbackComponent} onError={createLogError('ErrorItem')}> {/* å
éšã§ `throw new Error('ãªããåããšã©ãŒ');` ãå®è¡ããã³ã³ããŒãã³ã */} <ErrorItem /> </ErrorBoundary> ); } äžèšã®äŸã§ã¯ã³ã³ããŒãã³ãåããã®ãŸãŸIDã«å
¥ããŠããŸãããæ©èœã«å³ããååãå
¥ã£ãŠãããšãã£ãšãããããããªããšæããŸããããããã°åºåããã ãã§ããã°ãããã§åäºåã§ããã ãããã« ä»åã¯ErrorBoundaryãå©çšãããã°åºåã«ã€ããŠç޹ä»ããŸãããReactã®ã³ã³ããŒãã³ãã§çºçãããšã©ãŒã¯ãæ¢ããå Žæããªããã°ã©ããŸã§ãé¡ãæçµçã«ããŒãžå
šäœãèœã¡ãŠããŸããŸããæäœéãšã©ãŒãçºçããããªç®æã§ã¯ErrorBoundaryãèšå®ããŠãããäœè£ãããã°ãã°åºåã§ããããã«ããŠãããšèª¿æ»ãã¹ã ãŒãºã§ããã ãŸãããããããšã©ãŒãçºçããã³ã³ããŒãã³ããåã¬ã³ããªã³ã°ããããªã¬ãŒãFallbackComponentå
ã«çšæããããšãã§ããã®ã§ããšã©ãŒåŠçãšããã©ããªããªãå¥¥ãæ·±ãã§ãã ææ¥ã¯ãkiwi26ããã®èšäºã§ãã ãæ¥œãã¿ã«ïŒ åè react-error-boundary – npm
ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024 17æ¥ç®ã®èšäºã§ãã ã¯ããã« ããã«ã¡ã¯ïŒæ°å1幎ç®ã®äœè€ã§ãã çŸåšãžã§ãããŒãã®ïŒæç®ã§ãåºå¹¹ã·ã¹ãã ã°ã«ãŒãã«ãŠä»£çåºæ§åãã®ç³èŸŒããŒã«ã®éçºã»éçšãäž»ã«è¡ã£ãŠããŸãã ç§ãæ
åœããŠããéçºã®ïŒã€ã« ããã¥ã¡ã³ãã®Markdownå ããããŸãã ãã®éçºã§ã¯Starlightãšãããã¬ãŒã ã¯ãŒã¯ã䜿çšããã®ã§ãããã«ã€ããŠç޹ä»ããããšæããŸãïŒ èæ¯ ããŒã ã®èšèšæžç®¡çã«ã€ã㊠ç§ãçŸåšæå±ããŠããããŒã ã§ã¯åãŸã§Excelã ãã§ããŒã«ã®èšèšæžã管çããŠããŸããã ãã®åŸãNotionã«ç§»è¡ãã€ã€ããã®ã§ãããäžéšã¯Excelã«æ®ã£ããŸãŸã«ãªã£ãŠããŸãã ããŒã«ã®æ¹åæ¡ä»¶ãæ¥ãéã«èšèšæžä¿®æ£ãããã®ã§ãããExcelã»Notionãšãã«ãã€ã誰ããã©ããä¿®æ£ããã®ããéåžžã«åããã«ãããªã£ãŠããŸããã æ å ã® è² ã人ã«ãã£ãŠå€ãããããã®ã§ãããç¢ºèªæŽ©ããå®å
šã«åé¿ããããšã¯ã§ããŸããã ããã§ãèšèšæžãGitHubã§ç®¡çããããšãã話ã«ãªããŸãããéçºãšåãããã«ãã©ã³ããåããä¿®æ£ãå ããŠããã«ãªã¯ãšã¹ããæããããšã§ãä¿®æ£ç®æãç°¡åã«ææ¡ããããšãã§ããŸãããŸããå±¥æŽç®¡çãæ°ã«ããå¿
èŠããããŸããã ãµã€ãã®ãã¹ãã£ã³ã°ã«ã€ã㊠ã ã£ããGitHub PagesããããããïŒãšãªããŸãããä»åéžæè¢ã«ã¯å
¥ããŸããã§ããã ãªããªããèšèšæžã¯ã瀟å
éå®å
¬éã«ããŠãéçºä»¥å€ã®æ¹ãèŠããããã«ããããšããèŠä»¶ããã£ãããã§ãã GitHub pagesã¯å
¬éç¯å²ãçµããã®ã§ããããã®äžã§ GitHubã¢ã«ãŠã³ããæã€äººã«éã 瀟å
éå®å
¬éãã§ããŸãããããéçºä»¥å€ã®æ¹ã¯ GitHubã¢ã«ãŠã³ããæã£ãŠããªã ã®ã§é²èЧããããšãã§ããŸããã ãµã€ãïŒã€ãèŠãããã ãã«æåã®ã¢ã«ãŠã³ããçºè¡ããã®ã¯åŸçãšã¯èšããŸããã ãšãªããšã第ïŒã®çãšããŠAmazon S3ã䜿ã£ãéçwebãµã€ããã¹ãã£ã³ã°ãæãããŸãããAWSã®ä»ã®ãµãŒãã¹ãšçµã¿åãããããšã§é©åãªå
¬éç¯å²ãèšå®ããããšãã§ããŸãã ã©ããã£ãŠãµã€ããäœã£ãŠããã Webãã¬ãŒã ã¯ãŒã¯ã§æåã©ããã ãšNext.jsãDocusaurus, Nuxt.jsããããŸãããç§ã¯Astroãéžã³ãŸããã https://astro.build/ çç±ïŒïŒé«éãªWebãµã€ããäœããããš ããã¥ã¡ã³ãéãéåžžã«å€ãã®ã§ãã§ããã°è»œããµã€ãã«ããããšããã§ããAstroå
¬åŒããã® 2023 Web Framework Performance Report ã«ãããšãAstroã¯ä»ã®ãã¬ãŒã ã¯ãŒã¯ã«æ¯ã¹ãŠããã©ãŒãã³ã¹ãè¯ãããšãåãããŸãã çç±ïŒïŒMarkdownã§èšè¿°ã§ããããš Astroã¯ããã©ã«ãã§Markdownã«å¯Ÿå¿ããŠããŸããããã¥ã¡ã³ãããŒãžãªã®ã§ãèŠãç®ã«ããŸããã ããå¿
èŠããªããæè¡çãªå£ãé«ããªãã®ã§èª°ã§ãããã«æžãããšããç¹ã§åªããŠããŸããç§ã®ãããªæ°äººã§ãå°ã調ã¹ãã°æžãæ¹ãçè§£ããããšãã§ããŸãã 以äžã®çç±ã§Astroãæ¡çšããŸãããAstroã§ããã¥ã¡ã³ãããŒãžãäœãã«ã¯Starlightãšãããã¬ãŒã ã¯ãŒã¯ã䜿çšããŸãã Starlightãšã¯ https://starlight.astro.build/ https://starlight.astro.build/ https://starlight.astro.build/ Starlightãšã¯Astro補ã®ããã¥ã¡ã³ããµã€ãã«ç¹åããéçãµã€ãã®çæãã¬ãŒã ã¯ãŒã¯ã«ãªããŸãã å
¬åŒããã¥ã¡ã³ã ã¯æ¥æ¬èªèš³ãããŠããŸãã ãªããšãMarkdownãæžãããšã§ç°¡åã«1ããŒãžãäœãã¡ãããŸãã ãŸãã.md圢åŒã®ãã¡ã€ã«ã ãã§ãªãã.mdx圢åŒã®ãã¡ã€ã«ã«ã察å¿ããŠããŸãã ãšãªããšãStarlightã¯Astroãåºç€ãšããŠãããããMDXãã¡ã€ã«ã§ ãµããŒããããŠããUIãã¬ãŒã ã¯ãŒã¯ ïŒReactãSvelteãVueãªã©ïŒã§æ§ç¯ãããã³ã³ããŒãã³ãã䜿ããŸãïŒïŒïŒ Starlightèªäœã«ãã³ã³ããŒãã³ããä»å±ãããŠãããä»ã®UIãã¬ãŒã ã¯ãŒã¯ã䜿ããªããšãååãªãµã€ããäœããŸãã ä»ã«ããã£ã¬ã¯ããªæ§é ãèªåã§ããŒãžæ§é ã«ãªã£ãŠããããããµã€ãå
æ€çŽ¢ãç»é¢ã®ããŒã¯ã¢ãŒãã»ã©ã€ãã¢ãŒãåæ¿ãããã©ã«ãã§ä»ããŠããŸãã ãã£ãŠã¿ããïŒ æ°ãããããžã§ã¯ããäœæããã«ã¯æ¬¡ã®ã³ãã³ããå©ããŸãã äºåã«Node.jsãšnpmã®ã€ã³ã¹ããŒã«ãããŠãããŠãã ããã npm create astro@latest -- --template starlight ãããžã§ã¯ãåèšå®ãšäŸåé¢ä¿ãã€ã³ã¹ããŒã«ãããåŠããªã©ãèãããã®ã§çããŸãã ãããšãæ°åã§æ°ãããããžã§ã¯ããåºæ¥äžãããŸãã cdã³ãã³ãã§äœæãããã£ã¬ã¯ãã«ç§»åããæ¬¡ã®ã³ãã³ããå©ããŸãã npm run dev ãããšlocalhostã§éçºç°å¢ãç«ã¡äžãããŸãã Example Guide â ã®ãã¿ã³ãæŒããšGuidesãšReferenceã®2ã€ãåºãŠããŸãã GuidesçŽäžã«ããŒãžã远å ãããå Žåã¯ãguidesãã©ã«ãå
ã«æ°ãã.mdãã¡ã€ã«ãäœæããä»ãã¡ã€ã«åæ§ã«titleãèšå®ããŸãã ããšã¯ astro.config.mjs ã«ããŒãžã®è¿œå èšå®ãããããšã§ãããŒãžè¿œå ãã§ããŸãã ReferenceçŽäžã«æ°ããããŒãžãäœãããå Žåã¯ãreferenceãã©ã«ãå
ã«æ°ãããã¡ã€ã«ãã€ãããšãããŸã§ã¯åãã§ãã astro.config.mjs ãèŠããšããã®ãã©ã«ã㯠autogenerate ãæå¹ãšããŠãããããããã§èšå®ãããªããšããã©ã«ãå
ã®ãã¡ã€ã«ãèªåã§èªã¿åã£ãŠããŒãžè¿œå ããŠãããŸãã GuidesãšExample Guideã¿ããã«èŠªåé¢ä¿ãäœãããå Žåã¯ãæ°ãããã©ã«ããšãã®äžã«ãã¡ã€ã«ãäœãã astro.config.mjs ã«ã远å ããŠããããšåºæ¥äžãããŸãã ä»ã«ã ãµã€ãããŒã®ã¿ã€ãã«ãããŒãžã¿ã€ãã«ãšã¯å¥ã®ååã«ãã ããŒãžããšã«æ°å€ãä»ããŠãå°ããé ã«ããŒãžã䞊ã¹ãïŒããã©ã«ãã ãšABCé ïŒ ãããžãã€ããŠåŒ·èª¿è¡šç€ºã«ãã ããŒãžå
ç®æ¬¡ãèšå®ããŠãh2ã®èŠåºãã®ã¿ç®æ¬¡è¡šç€ºãã ãœãŒã·ã£ã«ã¡ãã£ã¢ã¢ã«ãŠã³ããžã®ãªã³ã¯ã远å ãã ãªã©è²ã
ãšèšå®ãã§ããŸãã ãã²å
¬åŒããã¥ã¡ã³ããèªãã§ã«ã¹ã¿ãã€ãºããŠã¿ãŠãã ããã æåŸã«ãã«ãããã«ã¯ã npm run build ã§distãã£ã¬ã¯ããªãçæããŠãããŸãã ããšã¯ãã®ãã£ã¬ã¯ããªãäŸãã°ãS3ã«çœ®ããéçwebãµã€ããã¹ãã£ã³ã°ã®èšå®ãããããšã§å
¬éã§ããŸãïŒ ãããã« ä»åã¯Starlightã䜿ã£ãŠç°¡åãªããã¥ã¡ã³ãããŒãžãäœã£ãŠã¿ãŸãããããŒããã©ãªãªãè¶£å³ç޹ä»ãªã©ã®ããŒãžäœãã§ãã²æ€èšããŠã¿ãŠãã ããïŒ ææ¥ã¯ Kazuhiro-27 ããã®èšäºã§ãã ãæ¥œãã¿ã«ïŒ ãããã£ã§ã¯ã ããŸããŸãªãããã¯ããžææŠãã ãšã³ãžãã¢ãçµ¶è³åéäžã§ãïŒ ãèå³ã®ããæ¹ã¯ä»¥äžã®æ¡çšãµã€ããã ãæ°è»œã«ãé£çµ¡ãã ããïŒ ãããã£æ ªåŒäŒç€Ÿæ¡çšæ
å ± Tech TalkãMeetUpãéå¬ããŠãããŸãïŒ ãã¡ãããæ°è»œã«ãå¿åãã ããïŒ Event – NIFTY engineering connpassã§ãããã£ã°ã«ãŒãã« åå ããã ããš ã€ãã³ãã® ãç¥ãããå±ããŸãïŒ connpassã§ ãããã£ã°ã«ãŒãã«åå ãã
ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024 16æ¥ç®ã®èšäºã§ãã ã¯ããã« ããã«ã¡ã¯ããããã£æ°åïŒå¹Žç®ã®è€å²¡ã§ãã äžäº¬ããŠå°ãçµã¡ãæºå¡é»è»ã«ãæ
£ããŠãã仿¥ãã®é ã§ãã ä»åã¯ãã³ã³ããåãããã¢ããªã±ãŒã·ã§ã³ãéçºããéã«çºçãããVScodeã§RancherDesktopãçšããŠéçºã³ã³ãããèµ·åã§ããªããåé¡ã«ã€ããŠåãäžãããã®åå ã調æ»ãã解決ã«è³ããŸã§ã®æé ãå
±æããŸãã 䌌ããããªåé¡ã«çŽé¢ããæ¹ã®åèã«ãªãã°å¹žãã§ãã DockerDesktopããRancherDesktopãžç§»è¡ ç§ãã¡ã®ããŒã ã§ã¯ã以åããDockerDesktopã䜿ã£ãŠã³ã³ããã®ç®¡çãè¡ã£ãŠããŸããã ããããDockerDesktopã®å©çšæãå€äžãããããããå
æ¥RancherDesktopã«ç§»è¡ããŸããã RancherDesktopã¯ãDockerDesktopåæ§ã«ã³ã³ããã®ç®¡çãç°¡åã«ããããã®ããŒã«ã§ãã DockerDesktopãšã®éãã«ã€ããŠè©³ããç¥ãããæ¹ã¯ã以äžã®èšäºãåèã«ãªããŸãã Rancher Desktopã®äœ¿ãæ¹ïœDocker Desktopãšã®éããç§»è¡æé ã解説 – ã«ãŽã€ã®ãµãŒããŒç 究宀 éçºã³ã³ãããéããªãåé¡ ç§»è¡èªäœã¯ã¹ã ãŒãºã§ããããåŸæ¥éãVScodeã§ã³ã³ãããèµ·åããããšãããšããæ¬¡ã®ãããªãšã©ãŒãçºçããŸããã [2024-12-06T08:03:03.507Z] Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/run/docker/containerd/daemon/io.containerd.runtime.v2.task/moby/32b5120f8d4e4e470a4e14b2d729750846f48652b9c01073e6fed43a8bc573a2/\\wsl.localhost\Ubuntu\mnt\wslg\runtime-dir\wayland-0" to rootfs at "/tmp/vscode-wayland-8287cccf-e6ca-4539-a913-14586d6ff8ee.sock": create mount destination for /tmp/vscode-wayland-8287cccf-e6ca-4539-a913-14586d6ff8ee.sock mount: bind mount source stat: stat /run/docker/containerd/daemon/io.containerd.runtime.v2.task/moby/32b5120f8d4e4e470a4e14b2d729750846f48652b9c01073e6fed43a8bc573a2/\wsl.localhostUbuntumntwslgruntime-dirwayland-0: no such file or directory: unknown ãšã©ãŒå
容ãèªã¿è§£ãããšè©Šã¿ãŸããããèŠæ
£ããªãçšèªãå€ããªããªãçè§£ã§ããŸããã§ããã ã³ã³ããç³»ã®ãšã©ãŒã¯ããšããããäžç©åèµ·åããšããããšã§ docker prune ãå®è¡ãããæ¹åããã AIã«çžè«ããŠã¿ãŠãããšã©ãŒå
å®¹ã¯æããŠãããŸããã解決ã¯ã§ããã ãã®ãšã©ãŒã¡ãã»ãŒãžã¯ãDockerã³ã³ããã®èµ·åäžã«çºçããåé¡ã瀺ããŠããŸããå
·äœçã«ã¯ãã³ã³ããã®åæåäžã«å¿
èŠãªãã¡ã€ã«ããã£ã¬ã¯ããªãèŠã€ãããªããããããŠã³ãã«å€±æããŠããŸãã 以äžã®æé ã§åé¡ã解決ã§ããã詊ããŠã¿ãŠãã ããïŒ 1.WSLã®åèµ·å: 2.DockerããŒã¢ã³ã®åèµ·å: 3.å¿
èŠãªãã£ã¬ã¯ããªã®ååšç¢ºèª: 4.DockerãšWSLã®æŽæ°: WaylandãšVScodeã®é¢ä¿ å
茩ã«çžè«ãããšãããããšã©ãŒæäžã® wayland ãåå ã§ã¯ïŒããšã®ææãåããŸããã 調ã¹ãçµæã wayland ã¯ãã£ã¹ãã¬ã€ãµãŒããããã³ã«ã®äžçš®ã§ãGUIã¢ããªã±ãŒã·ã§ã³ã®ç»é¢æç»ã管çãã圹å²ãæãããŠããããšãåãããŸããã ç°¡åã«èšããšããGUIã衚瀺ããããã«å¿
èŠãªæºåãããä»çµã¿ãã§ãã wayland ã«ã€ããŠã¯ãã£ãšåããããã説æããŠãããŠããèšäºãããã€ãããã®ã§èª¿ã¹ãŠã¿ãŠãã ããã ãã£ã¹ãã¬ã€ãµãŒããšã¯ – ãããããã解説 WeblioèŸæž VScodeã§ã¯éçºã³ã³ãããèµ·åããéãèªåçã« wayland ã®ãœã±ãããããŠã³ãããŸãã ããããRancherDesktopç°å¢ã§ã¯ãã®ããŠã³ããã¹ããµããŒããããŠããªãããããšã©ãŒãçºçããŠããããã§ãã è§£æ±ºæ¹æ³ 察åŠã¯ç°¡åã§ãVScodeã«ã wayland ãœã±ãããããŠã³ãããªãããã«èšå®ãããã ãã§ãã æ¹æ³ã¯CLIãšGUIã®äºéããããŸãã CLI Ctrl + Shift + P ã§ããŠãŒã¶ãŒèšå®ïŒJSONïŒããéããæ¬¡ã®ã³ãŒãã远èšããŸãã "dev.containers.mountWaylandSocket": false GUI VScodeå·Šäžã®æ¯è»ããŒã¯âèšå®âãwaylandãã§æ€çŽ¢âãMount Wayland Socketãã®ãã§ãã¯ãå€ããŸãã ããã§VScodeã¯èªåçã« wayland ãœã±ãããããŠã³ãããªããªããéçºã³ã³ããã®èµ·åãå¯èœã«ãªããŸãã ãåèã VSCode Dev ContainerãšRancher Desktopã§äœãã³ã³ããç°å¢ãWSLã| SIOS Tech.Lab RancherDesktopãšDockerDesktopã®éã ä»åã®ãšã©ãŒã¯RancherDesktopç¹æã®ãã®ã§ãDockerDesktopã§ã¯çºçããŠããŸããã§ããã DockerDesktopã¯è€éãªç°å¢èšå®ãããŸãåŠçããŠãããäžæ¹ãRancherDesktopã¯ãã®ç¹ã§å°ã
äžäŸ¿ãªéšåãããããã§ãã ãšã¯ãããRancherDesktopã«ã¯DockerDesktopã«ã¯ãªãã¡ãªããããããä»åŸã®ã¢ããããŒãã§ããã«äœ¿ãããããªãããšãæåŸ
ããŠããŸãã ãããã« ä»åã¯ãVScodeã§RancherDesktopã䜿ã£ãŠéçºã³ã³ãããèµ·åããéã«çºçãããšã©ãŒã®åå ãšè§£æ±ºæ¹æ³ã玹ä»ããŸãããè€æ°ã®ããŒã«ãçµã¿åãããéçºç°å¢ã§ã¯ã仿§ã®éãã«ããåé¡ãèµ·ãããã¡ã§ãã ç°å¢å·®ã«ããåé¡ãé²ãããã«ã³ã³ããæè¡ãåºãŸã£ãŠããŸããããã®åšèŸºããŒã«ã«ãã£ãŠã¯äŸç¶ãšããŠåé¡ãçºçããããšãçæããŸãããã·ã¹ãã ã®åäœåçãçè§£ããªããéçºãé²ããéèŠæ§ãåèªèããæ©äŒã«ãªããŸããã å°ãã§ãåæ§ã®åé¡ã§æ©ãæ¹ã®å©ãã«ãªãã°å¹žãã§ãã ææ¥ã¯ã[äœè€] ããã®[Starlightã䜿ã£ãç°¡åãªããã¥ã¡ã³ãããŒãžã®äœãæ¹]ã§ãã ãæ¥œãã¿ã«ïŒ
💡 はじめに 🪄 Maestroについて 💭 事前準備 💻 ローカルでの実装 🐱 GitHub Actionsでの実装 😎 成果 💁‍ ️ 補足 ð¡ ã¯ããã« ããã«ã¡ã¯ããããã£æ ªåŒäŒç€Ÿã®Linã§ãã å°æ¹Ÿåºèº«ã®ã¢ãã€ã«ã¢ããªãšã³ãžãã¢ãšããŠã瀟å
ã§ãã〠ãããã£ïŒ Android ã» iOS ïŒãã®éçºãæ
åœããŠãããŸãã ä»åã¯ããã€ããã㣠Android 2.8.1 ããå°å
¥ããMaestroãšGitHub Actionsã«ãããã¹ãèªååã«ã€ããŠã玹ä»ããŸãã ðª Maestroã«ã€ã㊠Maestro ã¯ãAndroidã»iOSã»React Nativeã»Flutterãªã©ã®åçš®ã¢ãã€ã«ãã©ãããã©ãŒã ã«å¯Ÿå¿ããããªãŒãã³ãœãŒã¹ã®è»œéUIãã¹ããã¬ãŒã ã¯ãŒã¯ã§ãã åºæ¬å©çšã¯ç¡æã§ãããCIãå°å
¥ãããš Maestro Cloud ã¯ææãµãŒãã¹ã§ãããã ããGitHub Actionsãå©çšããã°ç¡æã§åæ§ã®æ©èœãå®çŸã§ããŸãã ïŒç¯çŽã§ããè²»çšã¯ ãã¡ã ã§èšç®ã§ããŸãïŒ ä»åã¯ãã®è£æã玹ä»ããŸãã ð äºåæºå ãŸãã¯äžèšã®ã³ãã³ãã䜿ã£ãŠMaestroãã€ã³ã¹ããŒã«ããŸãããã curl -fsSL "https://get.maestro.mobile.dev" | bash ãããŠãããããããšãæŽçããŸãããã å®çŸã§ããããããªãšæãããšãäžèšã®éã䞊ã¹ãŠã¿ãŸããïŒ GitHub Actionsã®ãã«ãªã¯ã§å€æŽãããã°èªåçã«ãã¹ããããŒãå®è¡ è€æ°ç«¯æ«ã®ãã¹ãçµæã確èªã§ãã ãã¹ãçµæãGitHubã®ã³ã¡ã³ãã«èªåæçš¿ ãšããã³ã¹ãšããŠãã¹ãã®é²ç»ã確èªã§ãã ããããããšã¯æ¬åœã«ã§ããã®ãïŒïŒ çãã¯ãŸããã® YES ïŒ ã©ããã£ãŠå®çŸããã®ããäžç·ã«ãã£ãŠã¿ãŸãããïŒ ð ð» ããŒã«ã«ã§ã®å®è£
CIã«ãããã¹ãèªååãå®çŸãããããäžèšã®äžã€ã®ãã®ãå¿
èŠã§ãã ãã¹ããããã¢ã㪠Maestroãã¹ããã㌠Github Actionsã¯ãŒã¯ãã㌠ä»åã®äŸã¯åŒç€Ÿã®äŒå¡ã¢ããªã®ã ã〠ããã㣠ãã§å®è£
ããŸããã æåã«ã¢ããªã®build.gradleã«ã¢ããªããŒãžã§ã³ãååŸããã¿ã¹ã¯ã远å ããŸãã ïŒããã¯åŸã®GitHub Actionsã³ã¡ã³ãæ©èœã§äœ¿ãããŠããŸãïŒ // build.gradle.kts (Module :app) ... tasks.register("printVersionName") { println(project.android.defaultConfig.versionName) } Maestroãã¹ããããŒã¯äžèšã®éã远å ããŠãããŸãã éè€æäœã¯operationsã«ãŸãšãããã¹ããããŒã¯testsã«éçŽããŸãã . âââ maesto/ âââ operations/ â âââ init.yaml â âââ login.yaml â âââ skip_tutorial.yaml âââ tests/ âââ test_flow.yaml 䜿ãããoperationsãããŒã¯äžèšã®éãïŒ // init.ymal appId: ... --- - clearState - launchApp: permissions: notifications: allow - runFlow: when: visible: "ãã°ã€ã³" file: "../operations/login.yaml" - runFlow: when: visible: "ã〠ãããã£ãžãããã" file: "../operations/skip_tutorial.yaml" // login.ymal appId: ... --- - tapOn: "@nifty ID ãŸã㯠@niftyãŠãŒã¶ãŒå" - inputText: ${USER_ID} - tapOn: "ãã¹ã¯ãŒã" - inputText: label: Enter password text: ${PASSWORD} - tapOn: "ãã°ã€ã³" // skip_tutorial.ymal appId: ... --- - tapOn: "ãã¥ãŒããªã¢ã«ãã¹ããã" ãã¹ãçšã®testsãããŒäŸã¯äžèšã®éãïŒ // test_flow.yaml appId: ... env: USER_ID: ${USER_ID} # init.yamlããäžæžããå¿
èŠãªå Žåã¯èšå®ãã PASSWORD: ${PASSWORD} onFlowStart: - runFlow: file: "../operations/init.yaml" --- - startRecording: test_flow_recording # ããã«ãã¹ããæžã - stopRecording ããŒã«ã«ã§äžèšã®ã³ã¡ã³ããå®è¡ãããš maestro test maestro/tests/test_flow.yaml -e USER_ID="XXX" -e PASSWORD="XXX" ãã¹ããããŒãèªåçã«åãå§ããŸãã startRecordingãšstopRecordingãèšå®ãããŠããã®ã§ãå®è¡ç»é¢ã®é²ç»ãä¿åãããŠããŸãã ð± GitHub Actionsã§ã®å®è£
åäœã§ããMaestroãããŒãããã°ã次ã¯GitHub Actionsã®ã¯ãŒã¯ãããŒãäœããŸãããã .githubã®workflowsã§android_maestro_tests.ymlã远å ãããã . âââ .github/ âââ workflows/ âââ android_maestro_test.yml // android_maestro_tests.yml name: Maestro Test on: pull_request: branches: - master paths-ignore: - "**.md" jobs: test: name: Run Maestro Tests (API ${{ matrix.api-level }}) runs-on: ubuntu-latest timeout-minutes: 30 strategy: matrix: api-level: [ 28, 33, 34 ] include: - target: default arch: x86_64 profile: pixel_6 ram-size: 8192M disk-size: 4096M heap-size: 4096M steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up JDK uses: actions/setup-java@v4 with: java-version: "17" distribution: "zulu" - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm - name: AVD cache uses: actions/cache@v4 id: avd-cache with: path: | ~/.android/avd/* ~/.android/adb* key: avd-${{ matrix.api-level }} - name: Create AVD and generate snapshot for caching if: steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@v2 with: api-level: ${{ matrix.api-level }} target: ${{ matrix.target }} arch: ${{ matrix.arch }} profile: ${{ matrix.profile }} ram-size: ${{ matrix.ram-size }} disk-size: ${{ matrix.disk-size }} heap-size: ${{ matrix.heap-size }} emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none force-avd-creation: false script: echo "Generated AVD snapshot for caching." - name: Build app with Gradle (Production) run: ./gradlew assembleProductionDebug - name: Get apk path id: apk-path run: echo "path=$(find . -regex '^.*/build/outputs/apk/.*\.apk$' -type f | head -1)" >> $GITHUB_OUTPUT - name: Get app version run: | VERSION_NAME=$(${{ github.workspace }}/gradlew -q printVersionName) echo "APP_VERSION=${VERSION_NAME}" >> $GITHUB_ENV - name: Set up Maestro run: | curl -fsSL "https://get.maestro.mobile.dev" | bash ~/.maestro/bin/maestro --version || echo "Failed to execute maestro" - name: Run Maestro tests id: run-maestro-tests uses: reactivecircus/android-emulator-runner@v2 with: api-level: ${{ matrix.api-level }} target: ${{ matrix.target }} arch: ${{ matrix.arch }} profile: ${{ matrix.profile }} ram-size: ${{ matrix.ram-size }} disk-size: ${{ matrix.disk-size }} heap-size: ${{ matrix.heap-size }} emulator-options: -no-window -no-snapshot-save -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none script: | $ANDROID_HOME/platform-tools/adb install ${{ steps.apk-path.outputs.path }} ~/.maestro/bin/maestro test --format junit maestro/tests/ -e USER_ID="${{ secrets.TEST_USER_ID }}" -e PASSWORD="${{ secrets.TEST_PASSWORD }}" -e APP_VERSION=${{ env.APP_VERSION }} - name: Upload test record id: upload-test-record if: ${{ steps.run-maestro-tests.outcome == 'success' }} uses: actions/upload-artifact@v4 with: name: Android_SDK_API_${{ matrix.api-level }}(${{ env.APP_VERSION }}_Succeeded) path: "**.mp4" - name: Add test record to PR comment if: ${{ steps.upload-test-record.outcome == 'success' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # Prepare GitHub CLI if ! command -v gh &> /dev/null; then sudo apt-get install gh -y fi # Prepare PR comment comment="### ${{ env.APP_VERSION }}ãã¹ãæå(Android SDK API ${{ matrix.api-level }}) : [ã¬ã³ãŒããããŠã³ããŒããã](${{ steps.upload-test-record.outputs.artifact-url }})" # Post PR comment gh pr comment ${{ github.event.pull_request.number }} --body "$comment" - name: Upload test report id: upload-test-report if: ${{ steps.run-maestro-tests.outcome == 'failure' }} uses: actions/upload-artifact@v4 with: name: Android_SDK_API_${{ matrix.api-level }}(${{ env.APP_VERSION }}_Failed) path: | **.mp4 report.xml - name: Add test report to PR comment if: ${{ steps.upload-test-report.outcome == 'success' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # Prepare GitHub CLI if ! command -v gh &> /dev/null; then sudo apt-get install gh -y fi # Prepare PR comment comment="### ${{ env.APP_VERSION }}ãã¹ã倱æ(Android SDK API ${{ matrix.api-level }}) : [ã¬ããŒããããŠã³ããŒããã](${{ steps.upload-test-report.outputs.artifact-url }})" # Post PR comment gh pr comment ${{ github.event.pull_request.number }} --body "$comment" ãã®ã¯ãŒã¯ãããŒã§äžèšã®æ©èœãå®è£
ãããŸããïŒ ãšãã¥ã¬ãŒã¿ãŒã¯ãã¹ããããAndroid SDKããŒãžã§ã³ã®Pixel 6ãæå®ãå®è¡å®å®æ§ãä¿èšŒããããã«ram-sizeãdisk-sizeãšheap-sizeãããã©ã«ãå€ããé«ãæ°å€ã«èšå®ããŸãã ãšãã¥ã¬ãŒã¿ãŒãå©çšããããKVMãæå¹åããProductionã®apkããã«ãããŠã€ã³ã¹ããŒã«ãã¹ãèšé²ãããšãã¥ã¬ãŒã¿ãŒã«apkãã€ã³ã¹ããŒã«ããŠMaestroãã¹ããããŒãå®è¡ããŸã å®è¡æåãããããšãã¥ã¬ãŒã¿ãŒã®ãã£ãã·ã¥ãä¿åãããæ¬¡åå®è¡ããæã«åå©çšãããŸã å
ã»ã©è¿œå ããprintVersionNameã¿ã¹ã¯ã«ãããã¹ã察象ã¢ããªã®ããŒãžã§ã³ãèªåååŸããå®è¡é²ç»ãartifactã«èªåä¿åãããŠã³ããŒããªã³ã¯ãèªåçæããŠãã³ã¡ã³ãã«ãšããã³ã¹ãæ®ããŸã æåãããæåã³ã¡ã³ããèªåæçš¿ã倱æããã倱æã³ã¡ã³ããèªåæçš¿ ã¯ãŒã¯ãããŒã§äœ¿ãããIDãšãã¹ã¯ãŒãã GitHub â Settings â Secrets and variables â Actions ã®secretsã«ç»é²ããŸãããã ãããŠãèªåãã¹ãåãçèªã ð ææ 次åããªãªãŒã¹ãã«ãªã¯ãäœæãããéã«ãåªæãè© å±ããã°èªåãã¹ãåãå¬åã§ããŸãã éãããã¹ããããŒãæ°ããªåãåŒã³èµ·ããïŒèªååã®éãšãªãïŒ ãã§ããèªåãã¹ãåïŒ åè«ã§ã (ã»Ïã») äœãããªããŠãèªåãã¹ãåãèªåçã«å¬åããåäœããŸãã ãã¹ãæåã»å€±æããå Žåãå®è¡ãšããã³ã¹ãèªåçæãããããŠã³ããŒãããŠç¢ºèªã§ããŸãã çŽ æŽãããã§ããïŒ ãã¹ãçµæã¯äžç®ã§ç¢ºèªã§ããã¬ã³ãŒããããŠã³ããŒããããšå®è¡é²ç»ã確èªã§ããŸãã ðââïž è£è¶³ Maestroã¯äŸ¿å©ã§ãããããããèœãšã穎ãããã€ããããŸãïŒ Maestro 1.33.1以äžã§ã¯ã床ã
ãemulator not foundãã®åé¡ãçºçããŸã 詳现 ram-sizeãdisk-sizeãšheap-sizeãé«ãã«èšå®ããããGitHub Actions Runners ã®ã¹ããã¯ãå¢åŒ·ããããšã§ãããçšåºŠæ¹åã§ããŸã Maestroã¯WebViewã«åŒ±ããassertVisibleã¯åºŠã
倱æããŸã extendedWaitUntil ã远å ãããšãããçšåºŠæ¹åã§ããŸã 床ã
ãã¿ã³ã»æåãèªèã§ããªãåé¡ããããŸã 察象㮠contentDescription ã远å ãããæ¹åã§ããŸãïŒnull ã«ããªãã§ãã ããïŒ
ãšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒãããŠããŸãèŠå·ã§ãã2024幎12æ7æ¥ã« Developers CAREER Boost 2024 ã®æèŠªäŒã§LTãããŸãããåœæ¥ãçµæ§çŠã£ãŠçºè¡šããŠããªããããèšãã®å¿ãããªãããšããã®ããã£ãã®ã§ãå
容ã«ã€ããŠãããã§æ¹ããŠæžããŠã¿ãããšæããŸãã ãŸããèšç»çå¶çºæ§ã«ã€ããŠèªãããŠããæ¹ãåœæ¥å€ãããããã«ãç§ããããŸã§ã®1ã€ã®äŒç€Ÿã®äžã§ããã«ãããäºæããªãããšã«æè»ã«ååãã«åãçµãããããã§æ¥œãããªã£ãŠãããã ãªããšããããšãããããŸãããéåžžã«ææçŸ©ãªã€ãã³ãã§ããïŒ ããã»ã¹ã楜ããã§ãããïŒãšããã¡ãã»ãŒãžãšãšãã«ãç§ã®ãããã£æ°åãã20幎ã®ãšã³ãžãã¢ãã£ãªã¢ãéããŠå¹ã£ãŠããèªåæŠç¥ã«ã€ããŠã話ããããŠããã ããŸãã èªå·±çŽ¹ä» ãããã£æ ªåŒäŒç€Ÿã§ãšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒãåããŠããèŠå·äº®ãšç³ããŸãã2004å¹Žã«æ°åå
¥ç€ŸããŠãããããã¯ãšã³ããšã³ãžãã¢ãã¹ã¯ã©ã ãã¹ã¿ãŒããããŠçŸåšã®ãšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒãšãæ§ã
ãªåœ¹å²ãçµéšããŠããŸãããããã¯ãšã³ãåŸåã§ã¯äž»ã«OAuth2.0/OpenID Connectãªã©ã®èªèšŒã»èªå¯ç³»ã®éçºã«æºãã£ãŠããŸããã èªåæŠç¥ ç§ã®èªåæŠç¥ã¯ãããã®ãšãã®ç¶æ³ãç°å¢ã«ãããŠèªåãç©æ¥µçã«æ¥œãããæ¹æ³ãåŠã¹ãè¡åãããããšãããã®ã§ãããã®æŠç¥ã«ã€ããŠãç§ã®ãã£ãªã¢ã®åãã§ãŒãºã«æ²¿ã£ãŠè©³ãã説æããŠãããããšæããŸãã ããã¯ãšã³ããšã³ãžãã¢æä»£ ãšã³ãžãã¢ãšããŠæåã®ãã£ãªã¢ã§ã¯ãæ¥åžžçãªæäœæ¥ãéçšæ¥åãèªååã®ãã£ã³ã¹ãšããŠæããããšãå¿ãããŸãããé¢åãªäœæ¥ããã£ãŠããããããã©ããã£ãŠèªååã§ãããããšèããããšã§ãä»äºã«ã¯ã¯ã¯ã¯æãèŠåºãããšãã§ããŸãããããäžåèšããŸããæåäœæ¥ã¯èªååããŠãããã£ã³ã¹ã§ãã ãã°èª¿æ»ãèªååãããããã©ãŠã¶ã§ã®æåãããããã¹ã¯ã¬ã€ãã³ã°ãããããããã¯ãšã³ãæä»£ãšæžããŸããããå®ã¯ä»ã§ããããŒãžã£ãŒç¹æã®æ¿èªäœæ¥ã®çååãªã©å¯ãã«ãã£ãŠãããŸãããªããªããæ¥œããããã ããšã1åã®çååã§ãã£ãŠããããã500äººèŠæš¡ã®çµç¹ã§å±éããã°ã1æ¥8æéåãã€ãŸãããã£ãã人é1人ãéã£ãããšãšç䟡ãå°ããªæ¹åã®ç©ã¿éããã倧ããªäŸ¡å€ãçã¿åºãã®ã§ãã ã¹ã¯ã©ã ãã¹ã¿ãŒæä»£ ããŠãã€ã¥ããŠã¯ãã¹ã¯ã©ã ãã¹ã¿ãŒæä»£ã§ãã çãããçµéšããããããããŸãããç°å¢ãèªåã®ããŒã«ãå€ããããšã§ãæé·ãšããããçµéšå€ãé£èºçã«ããã£ãäœéšãããã®ã§ã¯ãªãã§ããããïŒ ç°å¢ãããŒã«ã®å€æŽã¯ãèªå·±æé·ã®å€§ããªãžã£ã³ãã¢ããã®ãã£ã³ã¹ã§ããã¹ã¯ã©ã ãã¹ã¿ãŒãšããŠãããŒã ãããžã¡ã³ãããã¡ã·ãªããŒã·ã§ã³ãå¿ççå®å
šæ§ãªã©ããããŸã§æªç¥ã ã£ãåéã«ææŠããããšãæ°é®®ã§æ¥œããã£ãã§ããæªç¥ãªãã®ãåŠã¶ããšèªäœæ¥œããã§ãããæ¥œãããåå¢ããã®ã¯ãç§ã¯ä»åŠãã ããšãããã«å®è·µã§ããããžã·ã§ã³ã«ããããšããããšã ã£ããšæããŸããåŠãã§ããã«è©Šããå Žããããšããããšã¯å¹žãã§ãã å³ã¯äžäŸã§ããã¬ããã¹ãã¯ãã£ãã®æ¹æ³ã«KPTããããšæããŸãããã¡ã³ããŒã®æ°æã¡ã«ããã¶ã£ãŠãããPROBLEMãŸã§ææ Œã§ããŠããªããããããæçŽãã®ãããªãã®ãåãåºããããã«ãKPTã«ãBOYAKIãã远å ããŸããŠãå®è·µããŠããäŸã§ãã ã§ãæ¹ããŠæ¯ãè¿ããšããèªå察ã¡ã³ããŒãšããæ§å³ããã§ãå§ããæä»£ã§ãããããããã€ãªããã«ãªã£ãŠåããŠåŸãããåŠã³ã£ãŠãããã ãªããšå®æããŸããã ãšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒæä»£ïŒ æåŸã¯ããšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒæä»£ã§ãã ãšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒãšãããšæåã¯äœããããããã®ã ããããšãããšããã§ããããå³ã®å³ïŒ engineering-management-triangle ïŒãæããŠãããŸãããããã¯ããšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒãã©ã€ã¢ã³ã°ã«ãšãããã®ã§ãEMã¯ããããã¯ããšããŒã ãšãã¯ãããžãŒã®éãåããååšã§ãããšãäŸãã°æ¡çšæŽ»åã§ããã°ããã¯ãããžãŒãšããŒã ã®éãããããã®ã«ãªããŸãã çŸåšã®ãšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒã®åœ¹å²ã¯ãç§ã®20幎ã®ãã£ãªã¢ã®äžã§æã楜ãããšæããŠããŸãããšããã®ã¯ãEMã£ãŠäœããããããã®ã ãããã§ã¯ãªããŠããäœããã£ãŠããã®äžã«ã¯ãŠã¯ãŸã£ãŠãããã ãªãããšããããšãããããå¿å°ããããçš®ã®ã³ãããæã®äžã§ãåŠç¿ãå®è·µãã§ããããšãã§ããŠããããšãã宿ãããŸããã³ãããæããšããã®ã¯èªèº«ã®æé·ãæããéšåã«ãããŠéèŠã§ãããçæ§ã¯ãã³ãããæãæããŠãã£ããããŸããïŒ ãšãããšããã§ãä»ãã20幎ããäžã§1çªèªç±ã§ãããä»äºã楜ãããšæããŠããŸããEMããããã ãšã³ãžãã¢ãªã³ã°ãããŒãžã£ãŒæä»£ïŒ ããã«ã人å士ãã€ãªãã圹å²ã楜ããããã»ã¹ãªã®ããšæ°ã¥ããæä»£ã§ããç§ã®å Žåã¯ããŸããŸãããEMæä»£ã§ãããããã£ãšæ©ããããã®ããã«ãããã¯ãŒãã³ã°ãããŠããæ¹ã¯ããã£ããããšæããŸããæ£çŽã矚ãŸããïŒ ãã£ããã¯äŒç€Ÿé¢ä¿ã§ãããã倧åŠã®ææãšãã³ã¯ãŒãã³ã°ã¹ããŒã¹ã«ããå
šãç°ãªãæ¥çš®ã®æ¹ãšè©±ããããå€éšã³ãã¥ããã£ã§äººãšäººãã€ãªã圹å²ã«å
¥ã£ããããŠã人å士ãã€ãªãã£ãŠãããã§ããŸããã³ã©ãã¬ãŒã·ã§ã³ã«æåãããããŸããããããæ¥œãã¿æ¹ããã£ããã å³ã®å³ã¯ä»ãå±ããŠããã€ã³ããŒãœãŒã¹ã³ã¢ã³ãºãžã£ãã³ã§ããããã¯ãOSSã§ã®éçºãã©ã¯ãã£ã¹ãäŒæ¥å
ã«æã¡èŸŒãã§ããªãŒãã³ãªãšã³ãžãã¢æåãæ ¹ãããããšãããã®ã§ããããèå³ãããŸããããã声ãããã ããã 宣äŒïŒ ãšãããšããã§å®£äŒãããŠãã ããã InnerSource Commons Community ã§ãïŒ å®£äŒïŒ 人ãšäººãã€ãªãããšèšãã°ããããã£ãäž»å¬ããããã¯ã€ãã³ãããããŸãã NIFTY Tech Day 2025 ä»åã§ïŒåç®ããã€ããªããéå¬ãèããŠãããŸãïŒæ¥ã2025幎2æ8æ¥ åææ¥éå¬ã§ãïŒããŒãã¯ãåŠã³ãã NIFTY Developersã®X ããæŽæ°æ
å ±ããåŸ
ã¡äžããïŒ ãŸãšã 1è¡ã§ãŸãšããŠã¿ããšãä»äºã®Whatã«ã€ããŠã¯äºæ¥èµ·ç¹ã§äŒç€Ÿã®äžã§ããŸããããç¶æ³ã«ãã£ãŠäœããããïŒèªåãäœã£ããïŒããŸãããHowã«ã€ããŠã¯ãåäººã®ææã§å€ããŠããããšããã ãšæããŸãã ãšããããšã§ãæ¥ã
ãããããããã©ãããã°ããã®ä»äºã¯æ¥œãããªãïŒåŠã³ãå¢ããïŒããšããããšãèªåã«åãç¶ããã¢ãããŒã·ã§ã³é«ããã£ãŠãããããšæããŸãã ã©ãããã°ããã®ä»äºã¯æ¥œãããªãïŒ ãšã³ãžãã¢äººç楜ããã§ããŸããïŒ ä»¥äžãç§ã®èªåæŠç¥ã§ããïŒ
ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024 11æ¥ç®ã®èšäºã§ãã ããã«ã¡ã¯ïŒ ä»åã¯ãJavaScriptãšTypeScriptã®äžå€§ã©ã³ã¿ã€ã ç°å¢ã§ããDenoãBunãNode.jsã«ã€ããŠæ¯èŒããŠããããšæããŸãã æŠèŠ Node.js: 2009幎ã«ç»å ŽããæãæçããJavaScriptã©ã³ã¿ã€ã Deno: 2018幎ã«Node.jsã®åµå§è
ã«ãã£ãŠéçºããããããå®å
šã§ã¢ãã³ãªã©ã³ã¿ã€ã Bun: 2022幎ã«ç»å Žããé«éã§å
šæ©èœãåããJavaScript/TypeScriptã©ã³ã¿ã€ã äž»ãªç¹åŸŽ Node.js åºå€§ãªãšã³ã·ã¹ãã ãšè±å¯ãªnpmããã±ãŒãž é·å¹Žã®å®çžŸãšå®å®æ§ éåæI/Oã«æé©å Deno ã»ãã¥ãªãã£éèŠïŒããã©ã«ãã§å®å
šïŒ TypeScriptã®ãã€ãã£ããµããŒã URLããŒã¹ã®ã¢ãžã¥ãŒã«ã€ã³ããŒã Bun é«éãªèµ·åãšã©ã³ã¿ã€ã å®è¡ Node.jsãšã®é«ãäºææ§ å
èµã®ããã±ãŒãžãããŒãžã£ãšãã³ãã©ãŒ æ¯èŒ ããã©ãŒãã³ã¹æ¯èŒç°¡åãªãã³ãããŒã¯ãšããŠãåã©ã³ã¿ã€ã ã§1ãã1000äžãŸã§ã®æ°ãæ°ããåŠçã®å®è¡æéãæ¯èŒããŠã¿ãŸãããã Node.js Homebrewãå
¬åŒãµã€ãïŒ https://nodejs.org/en ïŒãªã©ã§ã€ã³ã¹ããŒã«ãã benchmark.jsãšãããã¹ããã¡ã€ã«ãäœæããã console.log('Starting benchmark...'); const start = process.hrtime.bigint(); let count = 0; for (let i = 0; i < 10000000; i++) { count++; } const end = process.hrtime.bigint(); const duration = Number(end - start) / 1_000_000; // ããç§ããããªç§ã«å€æ console.log(`Counting completed in ${duration.toFixed(3)} ms`); console.log(`Final count: ${count}`); å®è¡ãã node benchmark.js å®è¡çµæ 1åç® $ node benchmark.js Starting benchmark... Counting completed in 7.381 ms Final count: 10000000 2åç® $ node benchmark.js Starting benchmark... Counting completed in 8.529 ms Final count: 10000000 3åç® $ node benchmark.js Starting benchmark... Counting completed in 8.092 ms Final count: 10000000 Deno Homebrewãªã©ã§ã€ã³ã¹ããŒã«ãã https://docs.deno.com/runtime/getting_started/installation/ benchmark.jsãšãããã¹ããã¡ã€ã«ãäœæããã console.log('Starting benchmark...'); const start = performance.now(); let count = 0; for (let i = 0; i < 10000000; i++) { count++; } const end = performance.now(); const duration = end - start; console.log(`Counting completed in ${duration.toFixed(3)} ms`); console.log(`Final count: ${count}`); å®è¡ãã deno run benchmark.js å®è¡çµæ 1åç® $ deno run benchmark.js Starting benchmark... Counting completed in 10.852 ms Final count: 10000000 2åç® $ deno run benchmark.js Starting benchmark... Counting completed in 10.905 ms Final count: 10000000 3åç® $ deno run benchmark.js Starting benchmark... Counting completed in 9.019 ms Final count: 10000000 Bun Homebrewãªã©ã§ã€ã³ã¹ããŒã«ãã https://bun.sh/docs/installation benchmark.jsãšãããã¹ããã¡ã€ã«ãäœæããã console.log('Starting benchmark...'); const start = process.hrtime.bigint(); let count = 0; for (let i = 0; i < 10000000; i++) { count++; } const end = process.hrtime.bigint(); const duration = Number(end - start) / 1_000_000; // ããç§ããããªç§ã«å€æ console.log(`Counting completed in ${duration.toFixed(3)} ms`); console.log(`Final count: ${count}`); å®è¡ãã bun benchmark.js å®è¡çµæ 1åç® $ bun benchmark.js Starting benchmark... Counting completed in 7.849 ms Final count: 10000000 2åç® $ bun benchmark.js Starting benchmark... Counting completed in 9.821 ms Final count: 10000000 3åç® $ bun benchmark.js Starting benchmark... Counting completed in 14.227 ms Final count: 10000000 çµæ ãã¹ãŠã»ãŒåçã®ããã©ãŒãã³ã¹ã瀺ããŠããŸãã HTTPãµãŒããŒäœæ ä»åºŠã¯åã©ã³ã¿ã€ã ã§ç°¡åãªHTTPãµãŒããŒãäœæããŠã¿ãŸãã Node.js server.jsãšãããã¡ã€ã«ãäœæããŸãã const http = require('http'); const server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello Worldn'); }); server.listen(3000, () => { console.log('Server running at http://localhost:3000/'); }); å®è¡ $ node server.js Server running at http://localhost:3000/ TypeScriptãã¡ã€ã«ã詊ããŠã¿ã server.tsãäœæãã import * as http from 'http'; const server: http.Server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello Worldn'); }); server.listen(3000, () => { console.log('Server running at http://localhost:3000/'); }); å®è¡ å®è¡ãããšãšã©ãŒ $ node server.ts (node:38672) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension. (Use `node --trace-warnings ...` to show where the warning was created) /Users/server.ts:1 import * as http from 'http'; ^^^^^^ SyntaxError: Cannot use import statement outside a module at wrapSafe (node:internal/modules/cjs/loader:1350:18) at Module._compile (node:internal/modules/cjs/loader:1379:20) at Module._extensions..js (node:internal/modules/cjs/loader:1518:10) at Module.load (node:internal/modules/cjs/loader:1249:32) at Module._load (node:internal/modules/cjs/loader:1065:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:158:12) at node:internal/main/run_main_module:30:49 Node.js v22.2.0 TypeScriptããã€ãã£ããµããŒãããŠããªãããšãåãããŸãã Deno server.tsãšãããã¡ã€ã«ãäœæããŸãã Denoã¯TypeScriptããã€ãã£ããµããŒãããŠããŸãã import { serve } from "https://deno.land/std@0.181.0/http/server.ts"; const handler = (req: Request): Response => { return new Response("Hello Worldn", { status: 200 }); }; console.log("Server running at http://localhost:3000/"); await serve(handler, { port: 3000 }); å®è¡ Denoã¯ã»ãã¥ãªãã£ãéèŠããŠããããããã¡ã€ã«ã¢ã¯ã»ã¹ããããã¯ãŒã¯ã¢ã¯ã»ã¹ã«ã¯ããŒããã·ã§ã³ãå¿
èŠã§ãã äŸãã°ããã¡ã€ã«èªã¿æžãã®å Žåã¯ä»¥äžã®ããã«ããŸãã deno run --allow-read --allow-write file_io.ts $ deno run --allow-net server.ts Server running at http://localhost:3000/ Listening on http://localhost:3000/ ãããã¯ãŒã¯ã¢ã¯ã»ã¹èš±å¯ïŒ--allow-netïŒãäžããªãã§å®è¡ãããšãèš±å¯ããŠããããšèãããŸãã $ deno run server.ts Server running at http://localhost:3000/ â Deno requests net access to "0.0.0.0:3000". â â Requested by `Deno.listen()` API. â â To see a stack trace for this prompt, set the DENO_TRACE_PERMISSIONS environmental variable. â â Learn more at: https://docs.deno.com/go/--allow-net â â Run again with --allow-net to bypass this prompt. â Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all net permissions) > Bun server.tsãšãããã¡ã€ã«ãäœæããŸãã Bunã¯TypeScriptããã€ãã£ããµããŒãããŠããŸãã const server = Bun.serve({ port: 3000, fetch(req) { return new Response("Hello Worldn"); }, }); console.log(`Listening on http://localhost:${server.port}`); å®è¡ $ bun run server.ts Listening on http://localhost:3000 DenoãšBunã®æ¯èŒ 1. ã¢ãžã¥ãŒã«ã®ã€ã³ããŒã: Deno: å€éšã¢ãžã¥ãŒã«ãURLããçŽæ¥ã€ã³ããŒãããŸãã import { serve } from "https://deno.land/std@0.181.0/http/server.ts"; Bun: çµã¿èŸŒã¿ã®ã°ããŒãã« Bun ãªããžã§ã¯ãã䜿çšãã远å ã®ã€ã³ããŒãã¯äžèŠã§ãã 2. ãµãŒããŒã®èšå®: Deno: serve 颿°ã䜿çšãããã³ãã©ãŒé¢æ°ãšèšå®ãªããžã§ã¯ããæž¡ããŸãã await serve(handler, { port: 3000 }); Bun: Bun.serve ã¡ãœããã䜿çšããèšå®ãªããžã§ã¯ããæž¡ããŸãã const server = Bun.serve({ ... }); 3. ãªã¯ãšã¹ããã³ãã©ãŒ: Deno: ç¬ç«ãã颿°ãšããŠå®çŸ©ããŸãã const handler = (req: Request): Response => { ... }; Bun: èšå®ãªããžã§ã¯ãå
ã® fetch ã¡ãœãããšããŠå®çŸ©ããŸãã fetch(req) { ... } æ¯èŒãã€ã³ã äžèšã®æ¯èŒçµæã§ã¯ãåã©ã³ã¿ã€ã ã® HTTP ãµãŒããŒå®è£
ã®éãããããŸããã 以äžã«ãäž»èŠãªæ¯èŒãã€ã³ãããŸãšããŸããã 1. TypeScript ãµããŒã : Node.js: 远å ã®ããŒã« (ts-node) ãšã¿ã€ãå®çŸ© (@types/node) ãå¿
èŠã Deno: ãã€ãã£ããµããŒãã Bun: ãã€ãã£ããµããŒãã 2. ã»ãã¥ãªãã£ã¢ãã« : Node.js: ããã©ã«ãã§ãã¹ãŠã®ã·ã¹ãã ãªãœãŒã¹ã«ã¢ã¯ã»ã¹å¯èœã Deno: æç€ºçãªæš©éä»äžãå¿
èŠïŒ --allow-net ãã©ã°ïŒã Bun: Node.js äºæã®ã¢ãã«ãæ¡çšïŒããã©ã«ãã§ã¢ã¯ã»ã¹å¯èœïŒã 3. APIèšèš : Node.js: æšæºç㪠http ã¢ãžã¥ãŒã«ã䜿çšã Deno: ã¢ãã³ãª Web æšæºã«åºã¥ãã APIã Bun: ã·ã³ãã«ãªãªããžã§ã¯ãããŒã¹ã® APIã 4. ã¢ãžã¥ãŒã«ã·ã¹ãã : Node.js: ES Modules (import æ§æ) ã䜿çšã Deno: ES Modules ãš URL ããŒã¹ã®ã€ã³ããŒãã䜿çšã Bun: çµã¿èŸŒã¿ã® Bun ãªããžã§ã¯ãã䜿çšã 5. å®è¡ã®ç°¡åã : Node.js: TypeScript ãçŽæ¥å®è¡ããã«ã¯è¿œå ã®ã»ããã¢ãããå¿
èŠã Deno: 远å ã®ã»ããã¢ãããªãã§ TypeScript ãçŽæ¥å®è¡å¯èœã Bun: 远å ã®ã»ããã¢ãããªãã§ TypeScript ãçŽæ¥å®è¡å¯èœã çµè« çµè«ãšããŠãNode.jsãDenoãBunã®3ã€ã®ã©ã³ã¿ã€ã ã¯ãããããç¬èªã®åŒ·ã¿ãæã¡ãJavaScriptãšã³ã·ã¹ãã ã®å€æ§åãšé²åã«å€§ããè²¢ç®ããŠããŸãã ãŸãããããã®ã©ã³ã¿ã€ã ã¯æ¥éã«é²åãç¶ããŠããããã宿çã«ææ°ã®ååããã§ãã¯ããå¿
èŠã«å¿ããŠéžæãèŠçŽãããšããå§ãããŸãã æ¬ããã°ããèªè
ã®çæ§ã®ãããžã§ã¯ãéžæãæè¡çãªæææ±ºå®ã®äžå©ãšãªãã°å¹žãã§ãã ããè©³çŽ°ãªæ
å ±ãå
·äœçãªäœ¿çšäŸã«ã€ããŠã¯ãåã©ã³ã¿ã€ã ã®å
¬åŒããã¥ã¡ã³ããåç
§ããããšããå§ãããŸãã ææ¥ã¯ãTsan0409ããã®èšäºã§ãããæ¥œãã¿ã«ã
ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024 10æ¥ç®ã®èšäºã§ãã CLIããŒã«ã瀟å
ã«ãã©ã€ããŒãtapãªããžããªãäœæãã瀟å
ã«é
åžããŸããã æå€ãšèšäºããªãã£ãã®ã§ãã®æ¹æ³ãã玹ä»ããŸãã ã¢ããªã±ãŒã·ã§ã³ã®ãªãªãŒã¹ã«äœ¿ã£ãŠããã®ã¯GoReleaserã§ãã ãã£ãã ãããã£æ ªåŒäŒç€Ÿã§ã¯çŸåšOneloginã䜿ã£ãŠããŸãã AWSã®IAM Roleã«AssumeRoleããéã¯ä»¥äžã®OneloginãæäŸããŠããããŒã«ã䜿ã£ãŠãã瀟å¡ãã»ãšãã©ã§ãã https://github.com/onelogin/onelogin-python-aws-assume-role ãã®ããŒã«ã¯javaçãããã®ã§ãããã©ã¡ãã«ããã©ã³ã¿ã€ã ã®ã€ã³ã¹ããŒã«ãå¿
èŠã§ãã ãŸãæ¯èŒçé »ç¹ã«æŽæ°ãããŠããããã§ã¯ãªããããããŒãžã§ã³ã«ãã£ãŠã¯äŸåã©ã€ãã©ãªã®åé¡ã§ã»ããã¢ããã倱æãããªã©ã®åé¡ããããŸããã ããã§ããããGoã§äœãçŽãããšã§ã·ã³ã°ã«ãã€ããªãã€ã»ããã¢ããäžèŠã«ãã€ã€ãbrewã§é
åžããããšã§MacãWSLç°å¢ãžã®å°å
¥ãããç°¡åã«ããããšæ±ºããŸããã ãµãŒãããŒãã£è£œã®ä»ã®ããŒã«ã䜿ããšããææ®µããããŸããããç§èªèº«ãã€ã³ãã©ç®¡çè
ã§ã¯ãªã(å
šç€Ÿåãã®éžå®æš©ããªã)ããšããçŸåšäœ¿ã£ãŠããããŒã«ããã®ç§»è¡ã¢ãããŒã·ã§ã³ãäžããããèšå®ãã¡ã€ã«ãæµçšããããšãéèŠã ã£ãããšãã€ã³ããŒãœãŒã¹åããããšã§ããæè»ã«éçºè
èªèº«ãå¿
èŠãªæ©èœã远å ããŠãããããšãéèŠããèªäœããããšã«åªäœæ§ããããšå€æããŸããã Tapãªããžããªã®äœæ ãã€ããªãé
åžããããã®tapãªããžããªãäœæããŸãã ãã®ãªããžããªã®åå㯠homebrew-<repo> ã®åœ¢åŒã§ããå¿
èŠããããŸãã https://docs.brew.sh/Taps#repository-naming-conventions-and-assumptions ãã©ã€ããŒããªtapãªããžããªãäœæããå ŽåãGitHubã®ããŒã¯ã³ã䜿ã£ãŠããŠã³ããŒãURLãäœãå¿
èŠããããŸãã 以äžã®Gistãéåžžã«åèã«ãªããããããã䜿ããŸãã https://gist.github.com/ZPascal/b21c652b811872b3f56db9d54d61d6c6 GitHubPrivateRepositoryDownloadStrategy ãšããã¯ã©ã¹ãããŠã³ããŒãæŠç¥ãšãªããŸãã æç€ºéããtapãªããžããªã®lib/é
äžã«é
眮ããŸãã ã¢ããªã±ãŒã·ã§ã³ã®äœæ ä»åã¯Homebrewã§é
åžããéšåãã¡ã€ã³ãªã®ã§ãããã§ã¯GoReleaserã®èšå®ã«ã€ããŠç޹ä»ããŸãã GoReleaserã¯ç°¡åã«è€æ°ã®OSãCPUã¢ãŒããã¯ãã£åãã«Buildãããããããªãã·ã¥ããããšãã§ããããŒã«ã§ãã https://github.com/goreleaser/goreleaser ãã®ããŒã«ã䜿ã£ãŠGitHub Actionsã§ãªãªãŒã¹ããŠããŸãã ã¢ããªã±ãŒã·ã§ã³ãªããžããªããtapãªããžããªã«pushããŠPRãäœæããå¿
èŠããããããPrivateAccessTokenãå¿
èŠã«ãªããŸãã ããŠã³ããŒãæŠç¥ãšããŠå
ã»ã©äœæãã GitHubPrivateRepositoryDownloadStrategy ã䜿ãããæå®ããŸãã .goreleaser.yaml version: 2 before: hooks: - go mod tidy - go generate ./... builds: - main: ./cmd/ binary: onelogin env: - CGO_ENABLED=0 goos: - linux - windows - darwin archives: - format: tar.gz name_template: >- {{ .ProjectName }}_ {{- title .Os }}_ {{- if eq .Arch "amd64" }}x86_64 {{- else if eq .Arch "386" }}i386 {{- else }}{{ .Arch }}{{ end }} {{- if .Arm }}v{{ .Arm }}{{ end }} format_overrides: - goos: windows format: zip changelog: sort: asc filters: exclude: - "^docs:" - "^test:" brews: - name: onelogin download_strategy: GitHubPrivateRepositoryReleaseDownloadStrategy custom_require: lib/private_strategy repository: owner: niftycorporation name: homebrew-tap branch: "{{ .ProjectName }}" token: "{{ .Env.PRIVATE_GITHUB_TOKEN }}" pull_request: enabled: true draft: false base: branch: master workflow name: Upload Release Asset on: push: tags: - 'v*' permissions: contents: write jobs: build: name: Upload Release Asset runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go uses: actions/setup-go@v5 with: go-version-file: go.mod cache: true - uses: goreleaser/goreleaser-action@v6 with: distribution: goreleaser version: "~> v2" args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PRIVATE_GITHUB_TOKEN: ${{ secrets.PRIVATE_GITHUB_TOKEN }} ãã®Workflowãå®è¡ããããšreleasesãäœæãããtapãªããžããªã«PRãäœæãããŸãã äžéšå€æŽããŠããŸããã以äžã®ãããªãã¡ã€ã«ãçæãããŸãã GoReleaserã䜿ããªããŠããã®ãããªãã¡ã€ã«ãããã°é
åžããããšèªäœã¯å¯èœã§ãã onelogin.rb # typed: false # frozen_string_literal: true # This file was generated by GoReleaser. DO NOT EDIT. require_relative "lib/private_strategy" class Onelogin < Formula desc "" homepage "" version "1.0.2" on_macos do on_intel do url "https://github.com/niftycorporation/onelogin-go-aws-assume-role/releases/download/v1.0.2/onelogin-go-aws-assume-role_Darwin_x86_64.tar.gz", using: GitHubPrivateRepositoryReleaseDownloadStrategy sha256 "hash" def install bin.install "onelogin" end end on_arm do url "https://github.com/niftycorporation/onelogin-go-aws-assume-role/releases/download/v1.0.2/onelogin-go-aws-assume-role_Darwin_arm64.tar.gz", using: GitHubPrivateRepositoryReleaseDownloadStrategy sha256 "hash" def install bin.install "onelogin" end end end on_linux do on_intel do if Hardware::CPU.is_64_bit? url "https://github.com/niftycorporation/onelogin-go-aws-assume-role/releases/download/v1.0.2/onelogin-go-aws-assume-role_Linux_x86_64.tar.gz", using: GitHubPrivateRepositoryReleaseDownloadStrategy sha256 "hash" def install bin.install "onelogin" end end end on_arm do if Hardware::CPU.is_64_bit? url "https://github.com/niftycorporation/onelogin-go-aws-assume-role/releases/download/v1.0.2/onelogin-go-aws-assume-role_Linux_arm64.tar.gz", using: GitHubPrivateRepositoryReleaseDownloadStrategy sha256 "hash" def install bin.install "onelogin" end end end end end brew installãã ãŸãããŒã«ã«ãããã©ã€ããŒããªããžããªã«ã¢ã¯ã»ã¹ããããã«PrivateAccessTokenãäœæãã HOMEBREW_GITHUB_API_TOKEN ãšããç°å¢å€æ°ã«æå®ããŸãã tapãªããžããªãæå®ããã€ã³ã¹ããŒã«ããŸãã ãã®ãšãããªããžããªåã® homebrew- éšåã¯çç¥ããããšãã§ããŸãã brew tap niftycorporation/tap brew install niftycorporation/tap/onelogin Brewfileã«ã¯ä»¥äžã®ããã«èšèŒããŸãã tap "niftycorporation/tap" brew "niftycorporation/tap/onelogin" ããã§ãã©ã€ããŒãã®tapãªããžããªã§ãã€ããªãé
åžããããšãã§ããŸããã ãŸãšã ãããŸã§ãã©ã€ããŒãã®tapãªããžããªãäœæããé
åžããæ¹æ³ã玹ä»ããŠããŸããã äŒæ¥å
ã§ç¬èªã®ãœãããŠã§ã¢ãé
åžãããããšã¯ãããªãã«å€ãããããªãããšæã£ãŠããŸãã ç¹ã«ä»¥äžã¯ããªãããããã€ã³ãã§ããã tapãªããžããªã®åœåèŠå PATã䜿ã£ãããŠã³ããŒãæŠç¥ã®äœæ PATã䜿ã£ãããŠã³ããŒãæŠç¥ã®æå® ä»ããã£ãŠããæ¹ãä»åŸããããšæã£ãŠããæ¹ã¯ãã²ãããã«æ°ãã€ããŠããã ããã°ãšæããŸãã ããããã¯ã¿ã€ãã«ã«é¢ä¿ã®ãªãä»åŸã®å±æã«ã€ããŠã§ããããã®ãªããžããªã¯çŸåšã€ã³ããŒãœãŒã¹ãšããŠç€Ÿå
å
¬éããŠããŠå©çšè
ãæ¯èŒçå€ããããžã§ã¯ãã«ãªã£ãŠãããšèããŠããŸãã ãããã³ã³ããªãã¥ãŒã¿ããªããªãå¢ãããæ·å±
ã®é«ããé¢å¿ãåŒããŠããªãããšãåé¡ããšæã£ãŠããŸãã ããŒã«èªäœã¡ã€ã³æ©èœã¯ã»ãŒå®æããŠããŸãããçéã§äœã£ããããªãã¡ã¯ã¿ãªã³ã°ãåŠçã®å¹çåãããã¥ã¡ã³ãã®æŽåãªã©ããããäºèªäœã¯ãŸã ãŸã ããç¶æ³ã§ãã ãŸããæ®æ®µäœ¿ããªãèšèªãé åã«è§Šãããªã©ãšã³ãžãã¢ãšããŠã®æé·ãæãããããã³ã³ããªãã¥ãŒã¿ãå¢ããã€ã³ããŒãœãŒã¹ãOSSã«èå³ãæã£ãŠããããããæŽ»åããŠããäºå®ã§ãã tapãªããžããªã«ã€ããŠãçŸåšé
åžãããŠããã®ããã®ããŒã«ã®ã¿ãšããããšãããå¯ããã®ã§ããã¡ããæ·å±
ãäžãããç°¡åã«è¿œå ã§ããããã«ãªãã°ãããªãšæ³åããŠããŸãã æåŸã«ããã®èšäºãã©ãªããã®ã圹ã«ç«ãŠã°å¹žãã§ãã ææ¥ã¯ã@hayabusa01 ããã®èšäºã§ãã ãæ¥œãã¿ã«ïŒ
ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024 9æ¥ç®ã®èšäºã§ãã ããã«ã¡ã¯ããããã£æ ªåŒäŒç€Ÿã® statiolake ã§ãã ç§ã¯çç²ã® Neovimmer ãªã®ã§ãããããã¯ãªãããšãããšèªåã®éçºç°å¢ãèªå奜ã¿ã«ã«ã¹ã¿ãã€ãºããããšã倧奜ãã ããã§ãã è€éã§èŠããŠããããªãåŠçãèªååããŠé èœããã·ã³ãã«ã§æå¿«ãªæäœã§å®è¡ã§ããããã«ããããšã³ãžãã¢ãªã³ã°ã®ç²ãšèšã£ãŠãããã§ãããããã®å¶ã¿ãæãé«éã«ã€ãã¬ãŒãã§ããããšãããèªåã®éçºç°å¢ãæŽããããšãªã®ã§ãã ãããªãè±ç·ããŠæçž®ãªã®ã§ãããå
æ¥éå¬ããã VimConf 2024 ã®ããŒããŒãã§ãNeovim ãã©ã°ã€ã³éçºè
ã§ã¹ããªãŒããŒã§ããã TJ DeVries æ°ããã®ãããªè¬æŒããããŠããŸããã ãã¡ããVimConf ãªãã Vim åºæã®è©±ã¯ã»ãŒãããŸããã®ã§ãã©ãªãã§ã楜ããã§ããã ãããšæããŸããèªãå£ã®è»œå¿«ãã¯ãããã¹ããªãŒããŒãšãã£ããšãããèããŠããŠé£œããããšããããŸããã§ããã ã€ãæè¿ YouTube ã«åç»ãäžãã£ããããªã®ã§ããããããé¡ãããŸãã äœã®è©±ã ã ãããããããããšããã£ãŠãç§ã¯ã¡ã¿ããã°ã©ãã³ã°ã倧奜ãã§ãã è€éã§æžããŠããããªããã€ã©ãŒãã¬ãŒããé èœããç°¡åã§çŽæçãªã³ãŒãã§åŒã³åºããããã«ãªããšããªããããã§ããããåçåä»ãã§æ§ã
ãªãã®ããªããžã§ã¯ããšããŠæ±ãã Python ã¯ãã³ãŒããç°¡åã«ãããããã«ããããšã«ãããŠã¯è¶
äžæµãšãã£ãŠè¯ãã§ãããã ä»åã¯ãããã£ãã¡ã¿ããã°ã©ãã³ã°ã§äœ¿ããããªãã¯ããã¯ã®äžã€ãšããŠãã¡ãœããã®ããªããããªããžã§ã¯ããäœãæ¹æ³ãåŠãã ã®ã§ãå
±æããããšæããŸãã ããã䜿ã£ããäœãã§ãããã¯ããŸããããå¥ã®èšäºã«ãããããããŸããã â» ãªããããã¯èšèªä»æ§ãªã©ã«ç«ã¡å
¥ã£ãå³å¯ãªè©±ã§ã¯ãªãããšãå
ãããŠãæãããŠãããŸãããããŸã§è©³ããããã§ã¯ãªãã§ãâŠ é¢æ°ã®ããªããããªããžã§ã¯ãã®äœãæ¹ ãããªãã¡ãœããã«å
¥ãåã«ãæ®éã®é¢æ°ã«ã€ããŠèããŠã¿ãŸãããã def add(a, b): return a + b print(add(1, 2)) # => 3 å®ã¯ã颿°ã®ããã«äœ¿ãããªããžã§ã¯ããäœãã®ã¯çµæ§ç°¡åã§ãã 確ãã«é¢æ°ã«ã¯ add(1, 2) ãšããç¹å¥ãªææ³ãäžããããŠã¯ããŸããããããããã¯å®ã¯ add.__call__(1, 2) ãšåãæå³ã«ãªã£ãŠããŸãããªã®ã§åã« __call__ ãšããããžãã¯ã¡ãœãããå®çŸ©ããŠãããã°åŒã³åºãæ§æã䜿ããããã«ãªããŸãã class AddFunction: def __call__(self, a, b): return a + b add = AddFunction() print(add(1, 2)) # => 3 # ^^^ AddFunction ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã§ããã颿°ã§ã¯ãªãããåŒã³åºãã å®ç§ã§ãã ã¡ãœããã¯ã©ãããŠé£ããã®ãïŒ ãããã§ãããªããå¥ã«ã¡ãœããã ã£ãŠåããããªæ°ãããŸãããã class Calculator: def add(self, a, b): return a + b c = Calculator() print(c.add(1, 2)) # => 3 å®éããããå
ã»ã©ã®ããã« __call__() ãæã£ããªããžã§ã¯ãã§çœ®ãæããŠãäžèŠã䜿ããŠããããã«èŠããŸãã class AddFunction: def __call__(self, a, b): return a + b class Calculator: # def add(self, a, b): # return a + b add = AddFunction() c = Calculator() print(c.add(1, 2)) # => 3 ããããããã«ã¯èŽåœçãªæ¬ ç¹ããããŸãããã㯠add() ãã€ã³ã¹ã¿ã³ã¹ã«çµã³ã€ããŠããªãããšã§ãã ã¡ãœãããªã®ã« self ã«çµã³ã€ããŠããªã äŸãã°é»åã® M+ ãã¿ã³ã®ããã«ãCalculator ã¯ã©ã¹å
ã«å€ãä¿æããã¡ãœãããäœããããšããŸããããããä»ã®åœ¢ã ãšãããå®è£
ã§ããŸããã AddFunction ã® __call__ ã«ãã self ã¯ãããŸã§ã AddFunction ã§ãã£ãŠ Calculator ã§ã¯ãªãããã§ãã ããããæ¯ãèããéã Python ã®ã¡ãœããã¯å°ãäžæè°ãªæ§è³ªãæã£ãŠããŸãã add() ãã¡ãœããã®å Žåã class Calculator: def add(self, a, b): return a + b c = Calculator() print(Calculator.add(c, 1, 2)) # => 3 print(c.add(1, 2)) # => 3 ãã®ããã« ã€ã³ã¹ã¿ã³ã¹.ã¡ãœããå(åŒæ°...) ã§åŒã³åºãããšãã¯èªåã§ self ã«ãªããžã§ã¯ããå
¥ãã ã¯ã©ã¹å.ã¡ãœããå(ã€ã³ã¹ã¿ã³ã¹, åŒæ°âŠ) ã§åŒã³åºãããšãã«ã¯ self ã«ããããã®ãèªåã§æå®ããããšãã§ããŸãã ãšããããä»äœã£ããªããžã§ã¯ãã䜿ã£ãŠã¿ããšâŠ class Calculator: add = AddFunction() c = Calculator() print(Calculator.add(c, 1, 2)) # ^ TypeError: AddFunction.__call__() takes 3 positional arguments but 4 were given print(c.add(1, 2)) # => 3 ãªããšã3 ã€ã®åŒæ°ã§åŒã³åºããšãããäŸå€ã«ãªã£ãŠããŸããŸããã確ãã« __call__() ã«ã¯ 2 ã€ã®åŒæ°ããå
¥ããããªãã®ã§ããšã©ãŒã«ãªãã®ã¯çè§£ã§ããŸãã ãããããªãã°ãªãã¡ãœããã¯ãšã©ãŒã«ãªããªãã®ã§ããããïŒ 2 ã€ã®åé¡ãšãããµãã«ãäŒãããŸããããæ¬è³ªçã«ã¯ 1 ã€ã ãã§ãã çµè«ããèšãã°ãéæ³ããããã®ã¯ã¡ãœããåŒã³åºãæã§ããã¡ãœãã add ã®æ¬åœã®å§¿ã¯ã ã¯ã©ã¹å.ã¡ãœããå ã§åŒã³åºãããã®ãšåãã self ãå«ãã 3 åŒæ°ã®é¢æ°ãšèããŠãã ããã ã€ãŸããPython ã ã€ã³ã¹ã¿ã³ã¹.ã¡ãœããå(åŒæ°...) ã®ãšãã ãåæã«ç¬¬äžåŒæ°ã«ã€ã³ã¹ã¿ã³ã¹ãçµã³ã€ããŠãããŠããããã£ãŠ 2 åŒæ°ã®é¢æ°ã®ããã«äœ¿ããŠããããšããããšã«ãªããŸãã æ®éã®ãªããžã§ã¯ããã¡ãœããã®ãµããããããã«ã¯ããã®ä»çµã¿ãèªåã§å®è£
ããªããã°ãããŸããããããŠãããå¯èœã«ããä»çµã¿ããã¹ã¯ãªãã¿ã§ãã ãã¹ã¯ãªãã¿ ããããå°ã蟌ã¿å
¥ã£ã話ã«ãªããŸãããPython ã«ã¯ãã¹ã¯ãªãã¿ãšãããã®ãååšããŸããæšæºã«ãã @property ãã³ã¬ãŒã¿ã®è£åŽã§äœ¿ãããŠããæ©èœã§ããããŸãã ãã¹ã¯ãªãã¿ ã¯ãã¡ãœããããã£ãŒã«ããååŸããããšãããšãã«å²ã蟌ãã§å¥œãåæãªãªããžã§ã¯ããè¿ãããšãã§ããæ©èœã§ãããŸãä»ã«ãã§ããããšã¯ãããã§ãããããã§ã¯å²æããŸãã ããšãã°ã以äžã® RandomValueDescriptor ã䜿ããšåç
§ãããã³ã«å€ãå€ãã£ãŠããäžæè°ãªãã£ãŒã«ããäœãããšãã§ããŸãã class RandomValueDescriptor: def __get__(self, instance, owner): return random.randint(1, 100) class Calculator: value = RandomValueDescriptor() c = Calculator() print(c.value) # => 34 (äŸ) print(c.value) # => 84 (äŸ) æ®éã®ãã£ãŒã«ãã®å Žåã value ã«ä»£å
¥ããŠãããªãã®ã«å€ãå€ãã£ãŠãããšããããšã¯ãããŸããã ããããã¹ã¯ãªãã¿ã䜿ããšã value ã«ã¢ã¯ã»ã¹ãããšãã«æ¯å __get__() 颿°ãéããŠãããããã«ãªããŸããããã§ã¯ããããã³ãŒããå®è¡ã§ããããããã®ããã«ãã©ã³ãã ãªå€ãè¿ãããšãã§ããããã§ãã ãããŠã __get__ ã«ã¯ããã€ãã®åŒæ°ããããŸãã ããã§çç®ãããã®ã¯ instance ã§ããããã«ã¯ ã€ã³ã¹ã¿ã³ã¹.ãã£ãŒã«ãå ã§åŒã°ããæã® ã€ã³ã¹ã¿ã³ã¹ ãäžããããŠããŸããããã«ãã¯ã©ã¹åãçµç±ããŠåŒã°ãããšã㯠None ãå
¥ã£ãŠããŸãã class InstanceDetectorDescriptor: def __get__(self, instance, owner): if instance is None: return "without instance" return "with instance" class Calculator: instance_detected = InstanceDetectorDescriptor() c = Calculator() print(Calculator.instance_detected) # => without instance print(c.instance_detected) # => with instance ãªãã»ã©ã instance ãèŠãŠã€ã³ã¹ã¿ã³ã¹ãããããªãããåãããšãã§ãããâŠããããããã§ãããïŒ ãã¹ã¯ãªãã¿ã§ã¡ãœããã®ããªããã ãããŸã§ã®èå¯ãèžãŸããŠã以äžã®ãã¡ memory_add() ã¡ãœããããªããžã§ã¯ãã«çœ®ãæããŠã¿ãŸãããã class Calculator: def __init__(self): self.memory = 0 def memory_add(self, delta): self.memory += delta c = Calculator() Calculator.memory_add(c, 1) # memory: 0 + 1 = 1 print(c.memory) # => 1 c.memory_add(1) # memory: 1 + 1 = 2 print(c.memory) # => 2 ãã®äžã®ãåŒæ°ã®æ°ãã€ã³ã¹ã¿ã³ã¹ãã©ããã§å€ãã£ãŠããéšåãé£ããã®ã§ããããããä»ã®æã
ã«ã¯ããã¹ã¯ãªãã¿ã䜿ã£ãŠä»¥äžã®ããšãå¯èœã§ãã åç
§ãããç¬éã __get__() ã§å²ã蟌ãããšãã§ãã __get__() ã®äžã§ã€ã³ã¹ã¿ã³ã¹ã®æç¡ããšãã奜ããªãã®ãè¿ãã ã§ããã°ãããã§ãããã ã€ã³ã¹ã¿ã³ã¹ãäžããããªãã£ããšãã¯ãæ®éã®é¢æ°ãè¿ãã ã€ã³ã¹ã¿ã³ã¹ãäžãããããšãã¯ãããã第äžåŒæ°ã«çŽã¥ããäžã€åŒæ°ãæžã£ã颿°ãè¿ãã class MemoryAddMethodDescriptor: def __get__(self, instance, owner): def inner(self, delta): self.memory += delta if instance is None: # ã€ã³ã¹ã¿ã³ã¹ããªãå Žå - ã¯ã©ã¹å.ã¡ãœããå(ã€ã³ã¹ã¿ã³ã¹, åŒæ°...) ã§åŒã³åºããã # æ®éã«é¢æ°ããã®ãŸãŸè¿ã return inner # ã€ã³ã¹ã¿ã³ã¹ãããå Žå - ã€ã³ã¹ã¿ã³ã¹.ã¡ãœããå(åŒæ°...) ã§åŒã³åºããã # 第äžåŒæ°ã«ã€ã³ã¹ã¿ã³ã¹ãäžããåŒæ°ãäžã€æžããã颿°ãäœã£ãŠè¿ã # ããã§ã¯æã£åãæ©ã lambda åŒã䜿ã£ãŠãã return lambda delta: inner(instance, delta) class Calculator: def __init__(self): self.memory = 0 memory_add = MemoryAddMethodDescriptor() ãããã¯ãã§ããããŠãå®è¡ããŠã¿ããšâŠ c = Calculator() Calculator.memory_add(c, 1) # memory: 0 + 1 = 1 print(c.memory) # => 1 c.memory_add(1) # memory: 1 + 1 = 2 print(c.memory) # => 2 æåã§ãïŒãããããã¡ããšã€ã³ã¹ã¿ã³ã¹ã«ãã¢ã¯ã»ã¹ã§ããŠããŸããã ããã§ã¯ __get__() ãè¿ããã®ããã ã®é¢æ°ã«ããŠããã®ã§ãããŸã䟿å©ãã宿ã§ããªããããããŸããã ããããããã§å
çšã®ã颿°ã®ãµãããããªããžã§ã¯ãããããæãããšãã§ããŠããŸããšãªãã°ãã©ãã§ããããïŒ ãããåºæ¬çã«ã¯æ®éã®ã¯ã©ã¹ã®æ®éã®ãªããžã§ã¯ãã§ãããããã®äžã«ã¡ãœããã远å ããããšãã§ããŸããããããããšâŠ ãããããªããšãã§ããŠããŸããŸãã é·ããªã£ãŠããŸãã®ã§ã仿¥ã¯ãããŸã§ã§ããã çµããã« ä»åã¯ã¡ãœããã®ãµãããããªããžã§ã¯ããäœã£ãŠã¿ãŸããããã¡ãããããã¯åäœã§ããã°æ®éã«ã¡ãœãããå®çŸ©ããã°è¯ãã倧ããæå³ãæã¡ãŸããããããããªããžã§ã¯ãã«ã¯å¥œãåæã«å¥ã®ãã£ãŒã«ããã¡ãœãããå¢ããããšãã§ããèªç±åºŠãé«ãŸããŸãã ããšãã°ãç§ã¯ãã®æ©èœãåäœãã¹ãã®ããã®ã¢ãã¯ã¯ã©ã¹ã«å¿çšããŠã¿ãŠããŸãã user = MockUserRepository() with user.get_all.patch([User(id=1, name="Alice")]): assert user.get_all() == [User(id=1, name="Alice")] ãã®äŸã§ã¯ã user.get_all ã®æ»ãå€ãäžæçã«äžæžãããæ©èœãæäŸããŠããŸãã get_all ã¯ã¡ãœããã®ããã«åŒã³åºããŸãããããã« patch() ãšããã¡ãœãããããã®ã¯ãä»åã®æ¹æ³ã䜿ã£ãŠãã¡ãœããã®ãµãããããªããžã§ã¯ããã«å·®ãæ¿ããŠããããã§ããå
·äœçã«ã¯ããŸãå¥ã®èšäºãæžããããããŸããã ãããªããã§ãã¡ãã£ãšããå°éå
·ã§ãããé·ãããä»ãåãããã ãããããšãããããŸããã¿ãªãããäœããåç¥ã®å°éå
·ãããã°ããã²æããŠãã ããïŒããšãTJ DeVries ããã®è¬æŒããã²èŠãŠã¿ãŠãã ããã ææ¥ã¯ãdev-shimada ããã®ã瀟å
TapãªããžããªãäœãèªäœããŒã«ãHomebrewã§é
åžãããã§ãã ãæ¥œãã¿ã«ïŒ
ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024 7æ¥ç®ã®èšäºã§ãã ã¯ããã« ããã«ã¡ã¯ãäŒå¡ã·ã¹ãã ã°ã«ãŒãã§ãšã³ãžãã¢ãããŠããå±±ç°ã§ãã çæ§ãCloudFront Functionsã¯äœ¿ã£ãŠããŸãã§ããããã CloudFrontã§ãšããžåŠçãè¡ãããå Žåã Lambda@Edge ããã㯠CloudFront Functions ã®ããããã䜿çšããããšã«ãªããŸããCloudFront Functionsã¯ã©ã³ã¿ã€ã ã®åŒ·ãå¶éã代åã«ãLambda@Edgeæ¯ã§æéãçŽ1/6ãšãå®äŸ¡ã«äœ¿çšããããšãã§ããŸãããããã£ç€Ÿå
ã§ãéçãµã€ãã§ã®ãªãã€ã¬ã¯ãåŠçãªã©ã«æŽ»çšããŠããŸãã 軜ãåŠçã§ãããšã¯ãããç¶ç¶çãªéçšãè¡ãã«ã¯åãã§ãã¯ããã¹ãã®æ©æµãåããããã®ã§ãã æ¬èšäºã¯ãã®ããã®ç°å¢ãã©ãæŽãããããšããå
容ã«ãªããŸãã çµè« çµè«ããå
ã«è¿°ã¹ããš TypeScriptã ãã§è¯ãå Žå: tscã§ãã©ã³ã¹ãã€ã«ãã ãã¹ãããããå Žå: ãã³ãã©ãŒã§ãã³ãã«åŸã æ£èŠè¡šçŸã§exportãé€å» ãã ãšãã圢ã«ãªããŸãã åæ åæãšããŠãCloudFront Functionsã¯ãµãŒããµã€ãJavaScriptã§ã¯ãããã®ã®ã Node.jsã§ã¯ãªã ã©ã³ã¿ã€ã ã§åäœããŸãããã®ããã以äžã®ãããªææ³äžã®å¶çŽããããŸãã(JavaScript 2.0ã©ã³ã¿ã€ã ã®å Žå) ECMAScript 5ããŒã¹ const/letãasync/awaitãªã©äžéšã®ES6ææ³ã«ãå¯Ÿå¿ ES Moduleséå¯Ÿå¿ CommonJSåãã®exportæ§æããšã©ãŒãšãªã module.exports ã¯moduleãundefinedã®ãããšã©ãŒ 1ãã¡ã€ã«ã®ã¿ãããã€å¯èœ ãããã®å¶çŽãæºããããã«äœãå¿
èŠããããŸãã å¯Ÿå¿æ¹æ³ åãã§ãã¯ã®ã¿ã§è¯ãå Žå åãã§ãã¯ãã§ããã°ããå Žåã¯ãTypeScriptã®å°å
¥ã®ã¿ã§è¯ãã§ãã pnpm add -D typescript tsconfigã®èšå®ã¯ä»¥äžã®ããã«ããŸãã { "compilerOptions": { "target": "es5", ... "baseUrl": "./src", "outDir": "./dist" }, "include": ["**/*.ts"], "exclude": ["node_modules", "dist"] } targetã¯ES5ã«ããŠãããŸããES6ææ³ã®å€ãã¯CloudFront Functionsã§ã䜿çšå¯èœã§ãããäžéšé察å¿ã®ææ³ã䜿çšããŠãæ°ã¥ããªããããES5ã«ããŠããã®ãç¡é£ã§ãããã æ¬¡ã«CloudFront Functionsçšã®åå®çŸ©ãçšæããŸããnpmããã±ãŒãžãšã㊠å
¬éãããŠãããã® ããããããããã䜿ããŸããæå
ã®ç°å¢ã§ã¯åæ
å ±ãããŸãåç
§ã§ããªãã£ããããå
容ãã³ããŒããŠå©çšããŠããŸãã declare namespace AWSCloudFrontFunction { interface Event { version: '1.0'; context: Context; viewer: Viewer; request: Request; response: Response; } interface Context { distributionDomainName: string; distributionId: string; eventType: 'viewer-request' | 'viewer-response'; requestId: string; } interface Viewer { ip: string; } interface Request { method: string; uri: string; querystring: ValueObject; headers: ValueObject; cookies: ValueObject; } interface Response { statusCode: number; statusDescription?: string; headers?: ValueObject; cookies?: ResponseCookie; } interface ValueObject { [name: string]: { value: string; multiValue?: Array<{ value: string; }>; }; } interface ResponseCookie { [name: string]: { value: string; attributes: string; multiValue?: Array<{ value: string; attributes: string; }>; }; } } CloudFront Functionsã®ãœãŒã¹ã«ã¯äžèšã®åãæå®ããŸãã function handler( event: CloudFrontFunction.Event ): AWSCloudFrontFunction.Request | AWSCloudFrontFunction.Response { ... } ããšã¯tscã§ã³ã³ãã€ã«ããã°JavaScriptãã¡ã€ã«ãåŸãããŸããåãã§ãã¯ã®ã¿ãè¡ãå Žåã¯å¥éã³ãã³ããçšæããŠãããšããã§ãããã tsc ãã¹ãããããå Žå ãã¹ããè¡ãããå Žåããã¹ãå¯Ÿè±¡é¢æ°ãexportããå¿
èŠãåºãŠããŸãããŸããã¡ã€ã«ãåå²ããããªãããšãããã§ãããããã®ãããåºæ¬çã«ãã³ãã©ã䜿ãããšã«ãªããŸãã ããããªããããã³ãã©ã®å¯Ÿå¿ãããããã®åºå圢åŒã§ãåé¡ãæ±ããŠããŸãã ESM圢åŒ: handlerã®exportãå¿
é ã export ~ ãææ³ãšã©ãŒ CJS圢åŒ: handlerã®exportãå¿
é ã module.exports = ~ ãmodule倿°ã®æªå®çŸ©ã«ãããšã©ãŒ IIFE圢åŒ: 颿°å®çŸ©ã倧ããå€ãã ESMãCJS圢åŒã§ã¯exportãããŠããªã颿°ã¯äžèŠãšå€æããããã³ãã«åŸã®çµæã«æ®ããªããªããŸããäžæ¹ã§exportãããšåºåçµæã«exportã®ææ³ãæ®ãããããšã©ãŒãåŒãèµ·ãããŠããŸããŸããããã㯠esbuildã®issue ã§ãè°è«ãããŠããŸãããããããHackyãªåé¿çãšãªã£ãŠããŸãã ããã§ã ESM圢åŒã§åºåãããã®ããexportãé€å»ãã ãšããã¢ãããŒããè¡ããŸãã ãã³ãã©ãšããŠä»åã¯tsupã䜿çšããŸãã pnpm add -D tsup 以äžã®ããã«èšå®ãè¡ããŸãã import { defineConfig } from 'tsup'; export default defineConfig({ entry: [ // åºåãããhandlerããããã¡ã€ã«çŸ€ ], format: 'esm', platform: 'node', splitting: false, sourcemap: false, minify: false, clean: true, }); entryã¯è€æ°æå®ã§ãããããè€æ°ã®é¢æ°ãã¡ã€ã«ãäžæ¬ããŠçæããããšãå¯èœã§ãã ãŸããã«ãåŸã®ãã¡ã€ã«ããexportãåãé€ãã¹ã¯ãªãããçšæããŠãããŸãã (ã³ãŒãã«ãã£ãŠã¯æ£èŠè¡šçŸã調æŽããå¿
èŠããããããããŸãã) /* ãã«ãåŸã®ãã¡ã€ã«ãå å·¥ããã¹ã¯ãªãã usage: node scripts/postbuild.js {build_dir} CloudFront Functionsã¯exportãè§£éã§ããªãããããã«ãåŸã®ãã¡ã€ã«ããexportãåé€ãã */ import * as fs from 'node:fs'; import * as path from 'node:path'; // exportæãå€å¥ããæ£èŠè¡šçŸ const regex = /export\s*{[^}]*};?/gs; const target = process.argv[2]; const targetPath = path.resolve(target); if (!fs.statSync(targetPath).isDirectory()) { console.error('Target is not a directory'); process.exit(1); } const files = fs.readdirSync(targetPath); for (const file of files) { const filePath = path.join(targetPath, file); const stats = fs.statSync(filePath); if (stats.isDirectory()) { continue; } const ext = path.extname(filePath); if (ext !== '.js') { continue; } console.log('Removing export statement from', filePath); const fileContents = fs.readFileSync(filePath, { encoding: 'utf-8' }); const newContents = fileContents.replace(regex, ''); fs.writeFileSync(filePath, newContents); } ããšã¯ãã«ãåŸã«ãã®ã¹ã¯ãªãããå®è¡ããããã«ããŠããã°OKã§ãã tsup && node postbuild.js ./dist ãŸãšã CloudFront FunctionsãTypeScriptã»ãã¹ãã«å¯Ÿå¿ããç°å¢ã§æžãããã®æ¹æ³ã«ã€ããŠè§£èª¬ããŸããã ã©ãããŠãããã¯æã®ããæ¹æ³ãåããããåŸãªãã®ã§ãããè¡ã£ãŠããããšã¯ã·ã³ãã«ãªã®ã§ä»ã®ãšããããã§éçšããããšãã§ããŠããŸãããã¹ãã«ã察å¿ã§ããããšã§ããªãã€ã¬ã¯ãã«ãŒã«å€æŽæã®ãã°ã¬é²æ¢ã«ã圹ç«ã£ãŠããŸãã CloudFront Functionsã®äžèº«ãè€éã«ãªã£ãŠããŠãåäœã®æ
ä¿ã«äžå®ãããæ¹ã¯è©ŠããŠã¿ãŠã¯ãããã§ããããã æ¬¡åã¯nunaããã®èšäºã§ãããæ¥œãã¿ã«ã
ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024  6æ¥ç®ã®èšäºã§ãã ã¯ããã« ããã«ã¡ã¯ããããã£æ ªåŒäŒç€Ÿã®äžŠæšã§ãã çããã¯ãã¿ã¹ã¯ã®å²ãåœãŠãé çªæ±ºãã«é ãæ©ãŸããããšã¯ãããŸãããïŒ ç§ã¯ãããŸã§ããªã³ã©ã€ã³ã®ãã¿ã ãããã«ãŒã¬ããããŒã«ãå©çšããŠããŸãããããã¿ã ããã®çµæãç®ã§è¿œã£ãããäœåºŠãã«ãŒã¬ãããåããããšãæå€ãšæéãããã£ãŠããŸããã ããã£ãšç°¡åã«ãäžçºã§æ©æ¢°çã«ã¿ã¹ã¯ãå²ãåœãŠãŠãããããŒã«ã欲ããïŒããšããæããããSlackã®ã¯ãŒã¯ãããŒãšZapierã䜿çšããŠãã¿ã¹ã¯ãç°¡åã«å²ãåœãŠãããŒã«ãäœæããŸããã ä»åã¯ããã®æ¹æ³ã«ã€ããŠã玹ä»ããããŸãã Slackã®ã¯ãŒã¯ãããŒãäœæãã Slackã§ã¯ãŒã¯ãããŒãæ°èŠäœæããŸãã ãSlackå
ã®ãªã³ã¯ããããéžæããŠãã ããã ã¹ãããã远å ããŸãã ããã©ãŒã ããéžæããŠãã ããã ãã©ãŒã ã®å
容ãèšå®ããŸãã 質å1ã§ã¿ã¹ã¯åãå
¥åããããèšå®ããŸãã 質å2ã§äººã®ååãå
¥åããããèšå®ããŸãã 質å1ã質å2ã§å
¥åãããå
容ããslackã«ã¡ãã»ãŒãžãšããŠéä¿¡ã§ããããèšå®ããŸãã ãã¡ãã»ãŒãžããéžæããŠãã ããã ããã£ã³ãã«ãžã¡ãã»ãŒãžãéä¿¡ããããéžæããŠãã ããã ä»åã¯ãã¯ãŒã¯ãããŒã䜿çšããããã£ã³ãã«ãã«ã以äžã®å
容ã®ã¡ãã»ãŒãžãéä¿¡ãããããèšå®ããŸãã ããã§ã¯ãŒã¯ãããŒã®äœæã¯å®äºã§ãïŒ Zapierãèšå®ãã ãŸãã¯ããªã¬ãŒã®èšå®ãããŸãã Appã¯ãSlackããTrigger eventã¯ãNew MentionããéžæããŸãã Slackã«ãã¿ã¹ã¯ç°¡åå²ãåœãŠã¯ãŒã¯ãããŒãèµ·åããŸãããããšããæç« ãæçš¿ããããZapierãèµ·åããããèšå®ãããã®ã§ãHighlight Wordã«ã¯ãã¿ã¹ã¯ç°¡åå²ãåœãŠã¯ãŒã¯ãããŒãèµ·åããŸãããããèšå®ããŸãã Trigger for Bot Messages?ã¯ãBotã«ããæçš¿ãããªã¬ãŒã®å¯Ÿè±¡ã«å«ãããã確èªããŠããŸãã®ã§ãä»åã¯ãTrueããéžæããŠãã ããã ã¿ã¹ã¯ãã©ã³ãã ã«å²ãåœãŠãåŠçãæžããŠãããŸãã Appã¯ãCode by ZapierããAction eventã¯ãRun PythonããéžæããŸãã èšèªã¯Pythonã®ã»ãã«Javascriptãéžæããããšãã§ããŸãã Input Dataã®å³åŽã®å
¥åããã¯ã¹ã«Slackã§æçš¿ãããæç« ãèšå®ããå·ŠåŽã®å
¥åããã¯ã¹ã«ããŒåãå
¥ããŸãã 以äžç»åã§ã¯ããŒåããoriginal_textããšããŸããããã©ããªååãã€ããŠãè¯ãã§ãã Codeã®äžã§ input_data['original_text'] ãšæžãããšã§ãInput Dataã§èšå®ããããŒã¿ãåãåºãããšãã§ããŸãã def custom_shuffle(lst): # ç°¡æçãªç䌌乱æ°çæ seed = sum(ord(c) for c in ''.join(lst)) for i in range(len(lst) - 1, 0, -1): seed = (seed * 1103515245 + 12345) & 0x7fffffff j = seed % (i + 1) lst[i], lst[j] = lst[j], lst[i] return lst # ã¯ãŒã¯ãããŒã䜿ã£ã人ã®ååãšã¿ã¹ã¯ãšäººåãåãåºã text = input_data['original_text'] lines = text.split('n') mention = lines[0] tasks = lines[4].split(',') people = lines[6].split(',') # ã¿ã¹ã¯ãšäººåãã·ã£ããã« tasks = custom_shuffle(tasks) people = custom_shuffle(people) # çµæãçæ result = "" for i in range(len(tasks)): person_index = i % len(people) # 人æ°ãè¶
ããå Žåã¯æåããå²ãåœãŠçŽã result += f"{tasks[i]}ïŒ{people[person_index]}n" output = [{'result':result, 'mention':mention}] ã¿ã¹ã¯ãå²ãåœãŠãçµæããSlackã«æçš¿ããŸãã Appã¯ãSlackããTrigger eventã¯ãSend Channel MessageããéžæããŸãã Channelã«Slackæçš¿ãããã£ã³ãã«åãMessage textã«Slackæçš¿ããã¡ãã»ãŒãžãå
¥åããŸãã Codeã®æåŸã« output = [{'result':result, 'mention':mention}] ãšèšèŒããŠããããšã§ãã¿ã¹ã¯ãå²ãåœãŠãçµæãšã¯ãŒã¯ãããŒã䜿ã£ã人ã®ååãåãåºããŠãã¡ãã»ãŒãžã«å«ããããšãã§ããŸãã ããã§Zapierã®èšå®ã¯å®äºã§ãïŒ å®éã«åãããŠã¿ã ã¯ãŒã¯ãããŒãå®è¡ããã¿ã¹ã¯åãšååãã«ã³ãåºåãã§å
¥åããŸãã ãéä¿¡ããããæŒäžãããšãã¯ãŒã¯ãããŒãå®è¡ãããã£ã³ãã«ã«ã以äžã®ã¡ãã»ãŒãžãæçš¿ãããŸãã ããã«æ°ç§åŸ
ã€ãšãã¿ã¹ã¯ãå²ãåœãŠãçµæãã#bot_ã¿ã¹ã¯å²ãåœãŠããã£ã³ãã«ã«æçš¿ãããŸãïŒ ããã㫠以åã®èšäºã Zapierã§Xæçš¿ããAPIãåŒã³åºããŠçµæãSlackã«éç¥ããŠã¿ã ãã§ã¯ãZapierãã Slackãžã®é£æºã詊ããŸããããä»åã¯éã« Slackã®æçš¿ãããªã¬ãŒã«ã㊠Zapierãèµ·åãããæ¹æ³ãåããŠå®è·µããŸããã ä»åŸããSlackãšZapierã®é£æºã掻çšããŠãæ¥åå¹çåãæ
å ±å
±æã®æ¹åã«åœ¹ç«ã€ããŒã«ãéçºããŠãããããšæããŸãã ææ¥ã¯ã jimmysharp ããã®ãCloudFront Functionsã§ãTypeScript&ãã¹ãããããã§ãã ãæ¥œãã¿ã«ïŒ
ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024  5æ¥ç®ã®èšäºã§ãã ã¯ããã« ãããã£ã§WEBãµãŒãã¹ã®éçºã»éçšãæ
åœããŠããæž¡éã§ãã æè¿ãéçšã®æéããããã«WEBãµãŒãã¹ãç«ã¡äžããæ¹æ³ã¯ãªãããªãšèããŠãããšãããAWS App RunnerïŒä»¥äžApp RunnerïŒã«åºäŒããŸããã ãã®èšäºã§ã¯ãApp Runnerã®ç¹åŸŽãä»ã®ãµãŒãã¹ãšã®éãã«ã€ããŠæžããŠãããŸãã App Runnerãšã¯ App Runnerã¯AWSã®ãµãŒãã¹ã®1ã€ã§ãã³ã³ããã¢ããªã±ãŒã·ã§ã³ãç°¡åã«ãããã€ã»éçšã§ãããã©ãããã©ãŒã ã§ãã Gitã®ã³ãŒããã³ã³ãããAWSã«ã¢ããããŒãããã ãã§ç°å¢ãäœããã®ã§ãã€ã³ãã©åšããæ°ã«ããå¿
èŠããããŸããã ECSïŒFargateïŒãããŒã¹ã«ããŠããã®ã§ãè² è·ã«å¿ããŠèªåçã«ã¹ã±ãŒã«ããã®ãç¹åŸŽã§ãã ãŸããVPCãããŒããã©ã³ãµãŒã®èšå®ãäžèŠãªã®ã§ããããã¯ãŒã¯ã®ç¥èããªããŠã䜿ããŸãã ä»ã®AWSãµãŒãã¹ãšã®éã AWSã«ã¯äŒŒããããªãµãŒãã¹ãããã€ããããŸãããApp Runnerã¯ããšã«ããç°¡åã«äœ¿ãããããšãéèŠããŠäœãããŠããŸãã äž»ãªãµãŒãã¹ãæ¯ã¹ãŠã¿ãŸãããã ãµãŒãã¹ ã¡ãªãã ãã¡ãªãã Amazon EC2 ⢠ãµãŒããŒãèªç±ã«èšå®ã§ãã ⢠OSãããã«ãŠã§ã¢ãèªåã§éžã¹ã ⢠ã©ããªçšéã§ã䜿ãã ⢠管çãå€§å€ â¢ äºæ³ä»¥äžã«è²»çšããããããšã Amazon ECS â¢ã³ã³ããéçšã«äŸ¿å© ⢠Fargateãªãéçšã楜 ⢠èªåã§ã¹ã±ãŒã«ãã ⢠ã€ã³ãã©ã®ç¥èãå¿
èŠ â¢ åæèšå®ãé¢å Elastic Beanstalk ⢠ãããã€ãç°¡å ⢠AWSã®ä»ãµãŒãã¹ãšé£æºãããã ⢠ãµãŒããŒç®¡çäžèŠ â¢ èªåã§ã¹ã±ãŒã«ãã ⢠AWSãžã®äŸåã匷ããªã ⢠åæèšå®ãé¢å AWS App Runner ⢠ãããã€ãç°¡å ⢠ã·ã³ãã«ãªèšå®é
ç® â¢ éçšã®æéãªã ⢠GitãDockerãããã䜿ãã ⢠èªåã§ã¹ã±ãŒã«ãã ⢠现ããèšå®ãã§ããªã ⢠AWSãžã®äŸåã匷ããªã èšå®é
ç® èšå®ããé
ç®ãå°ãªããŠãç»é¢ã®æµãã«æ²¿ã£ãŠé²ããã ãã§äœ¿ããŸãã WAFãèšå®ã§ããã®ã§ãIPå¶éããããã瀟å
åãã®ã¢ããªãäœããããã§ãã ã³ã¹ã ããã³ããšããã¯ãšã³ããåããã¢ããªãäŸã«ãã³ã¹ããèšç®ããŠã¿ãŸããã ãã©ãã£ãã¯ïŒ æé50äžãªã¯ãšã¹ã 1ãªã¯ãšã¹ããããå¹³å200ããªç§ ãªãœãŒã¹èŠä»¶ïŒ ããã³ããšã³ãïŒ1 vCPUã2GBã¡ã¢ãª ããã¯ãšã³ãïŒ2 vCPUã4GBã¡ã¢ãª ãµãŒãã¹ ã¿ã¹ã¯/ã€ã³ã¹ã¿ã³ã¹ ALB NAT Gateway ããŒã¿è»¢é åèš ECS Fargate $138.66 $20.20 $32.40 $57.36 $248.62 EC2 $46.80 $20.20 $32.40 $57.36 $156.76 App Runner $195.75 äžèŠ äžèŠ äžèŠ $195.75 èšç®åŒ ECSïŒfargateïŒ ããã³ããšã³ã vCPU ã³ã¹ãïŒ $0.05056 à 1 vCPU à 750æé = $37.92 ã¡ã¢ãª ã³ã¹ãïŒ $0.00553 à 2GB à 750æé = $8.30 åèšïŒ$37.92 + $8.30 = $46.22 ããã¯ãšã³ã vCPU ã³ã¹ãïŒ $0.05056 à 2 vCPU à 750æé = $75.84 ã¡ã¢ãª ã³ã¹ãïŒ $0.00553 à 4GB à 750æé = $16.60 åèšïŒ$75.84 + $16.60 = $92.44 EC2 ããã³ããšã³ãïŒ $0.0208 à 750æé = $15.60 ããã¯ãšã³ãïŒ $0.0416 à 750æé = $31.20 ããŒã¿è»¢éã®ä»®å®æ¡ä»¶ ALBçµç±ïŒã¯ã©ã€ã¢ã³ã â FargateïŒïŒ å¹³åãªã¯ãšã¹ããµã€ãºã1MBãšä»®å® ããŒã¿è»¢ééïŒ500,000ãªã¯ãšã¹ã à 1MB = 500GB NAT Gatewayçµç±ïŒFargate â ã€ã³ã¿ãŒãããïŒïŒ ããŒã¿è»¢ééïŒ10GB/æ ããŒã¿è»¢éã³ã¹ã ALB çµç±ïŒ (500GB - 1GBç¡ææ ) à $0.114 = $56.91 NAT Gateway çµç±ïŒ 10GB à $0.045 = $0.45 åèšããŒã¿è»¢éã³ã¹ãïŒ $56.91 + $0.45 = $57.36 ã³ã¹ãé¢ã§ã¯EC2ãæãå®äŸ¡ã§ãããéçšã®æéãèãããšApp RunnerãæªããªãããªãšæããŸãã App Runnerã®è£åŽã¯ECSïŒFargateïŒã®ãããåãç°å¢ã§ãããªããå®ããªãããšãããããŸãã ããã«ãApp Runnerã¯å®è¡æéããŒã¹ã®èª²éäœç³»ãæ¡çšããŠãããããã³ã¹ãã®äºæž¬ã容æãšããå©ç¹ããããŸãã App Runnerã®å¶éãšèæ
®ãã¹ããã€ã³ã ARM64ããµããŒãããŠããªã èšäºå·çæç¹ã§ã¯ARM64ã®ã³ã³ããã€ã¡ãŒãžã«ã¯å¯Ÿå¿ããŠããªããããx86_64ã¢ãŒããã¯ãã£ã®ã€ã¡ãŒãžã䜿çšããå¿
èŠããããŸãã ARM64ã¯ãã³ã¹ããšããã©ãŒãã³ã¹ã®äž¡é¢ã§ã¡ãªããããããããä»åŸã®å¯Ÿå¿ã«æåŸ
ã§ãã ã«ã¹ã¿ãã€ãºæ§ã®å¶é ãšã«ããç°¡åã«äœ¿ããããšãéèŠããŠããã®ã§ã现ããèšå®ã¯ã§ããŸããã ç¹ã«VPCæ¥ç¶ããã°èšå®ãªã©ã®é«åºŠãªæ§æãå¿
èŠãªå Žåãäœæ¥ãè€éã«ãªãããšããããŸãã ãªãŒãã¹ã±ãŒãªã³ã°ã®ææšãéå®ç åæå®è¡æ°ã§ããã¹ã±ãŒã«ã§ãããCPUãã¡ã¢ãªã®äœ¿çšçã§ã¯å¶åŸ¡ã§ããŸããã ãã®ãããç¹å®ã®ã¢ããªã±ãŒã·ã§ã³ã§ã¯ã¹ã±ãŒãªã³ã°èŠä»¶ãšã®äžäžèŽãçããå¹ççãªéçšãé£ãããªãå¯èœæ§ããããŸãã ãµã€ãã«ãŒã³ã³ããéå¯Ÿå¿ ãµã€ãã«ãŒã³ã³ããã䜿ããªãã®ã§ããã°åéãã¢ãã¿ãªã³ã°ãããæã«å·¥å€«ãå¿
èŠã§ãã ãŸãšã ã³ã³ããã䜿ãã®ãåœããåã«ãªã£ãŠããä»ãã·ã³ãã«ãªWEBãµãŒãã¹ãäœããªãApp Runnerã¯ããªã䜿ãããšæããŸãã å®éã«è©ŠããŠã¿ãããçŽ20åã»ã©ã§ã¢ããªã±ãŒã·ã§ã³ãAWSäžã§åäœã§ããããã«ãªããŸããããããã¿ã€ãã瀟å
ããŒã«ãäœãã®ã«ãŽã£ããã§ããã ã€ã³ãã©ã®å¿é
ãããã«éçºã«éäžã§ããã®ããå人çã«ãããæ°ã«å
¥ã£ãŠããŸãã ãã ã现ããèšå®ãã¹ã±ãŒãªã³ã°ãå¿
èŠãªå Žåã¯ãECSãEC2ãæ€èšããæ¹ããããããããŸããã åè AWS App Runner AWS Fargate Amazon EC2 AWS Elastic Beanstalk
ã¯ããã« ãããã£ã°ã«ãŒã Advent Calendar 2024 2æ¥ç®ã®èšäºã§ã ïŒ ã¯ãããŸããŠïŒ ç§ã¯ãµãã·ã¹ãšåŒã°ããããŒã ã«æå±ããŠãããæ®æ®µã«ã¹ã¿ããŒãµããŒãã»ã³ã¿ãŒ(以éCS)åãã®ã¢ããªã±ãŒã·ã§ã³ã®éçºãšéçšãæ
åœããŠããŸãã CSåãã®ã¢ããªã±ãŒã·ã§ã³ã¯ããã±ãŒãžã¢ããªã±ãŒã·ã§ã³ãå©çšããã ãã§ãªããå®å
šå
補ã®ã¢ããªã±ãŒã·ã§ã³ã®äœæãªã©ãè¡ã£ãŠããŸãããµãã·ã¹ã§ã¯ããããã®å
補ããŒã«ã®ãããã€ã¯ Terraform ãš AWS SAM ã䜿çšããŠããŸãã æ¬èšäºã§ã¯ããããã®ããŒã«ãéžæããçç±ãšãå®éã®äœ¿ã£ãŠã¿ãéçºã¡ã³ããŒã®å£°ã玹ä»ããŠãããããšæããŸãã IaCã®éžæè¢ ãããã€å
ã¯AWSãšããŸããAWSã§å©çšå¯èœãªIaCã®äžèЧã¯ä»¥äžã®éãã§ãã Cloudformation AWS CDK AWS SAM AWS Chalice Serverless Frameworks Terraform Pulumi åããŒã«ã®èª¬æã«ã€ããŠã¯ãããã§ã¯å²æããŸãã çŸåšãµãã·ã¹ã§ã¯ãECSãªã©ãå«ãã¢ããªã±ãŒã·ã§ã³ã¯ TerraformãLambdaã®ã¿ã§å®çµããããŒã«ã¯AWS SAMã䜿çšããŠããŸãã ããŒã«ã®éžå®çç± ããããã®ããŒã«ãéžãã çç±ã«ã€ããŠãåããŒã«ã®é·æãšçæã亀ããªãã説æããŠãããŸãã Terraform åªçæ§ãæ
ä¿ããã Terraformã¯å®£èšåã®IaCãšããŠèšèšãããŠãããç¶æ
ãtfstateãã¡ã€ã«ãçšããŠç®¡çããŸãããããã€ã«ã¯AWSã®APIãå©çšããŠãããAPIã®åŒã³åºãçµæãå
ã«ãtfstateãã¡ã€ã«ãæŽæ°ããããšã§åªçæ§ãæ
ä¿ããŠããŸãããŸãããããã€æã«ã¯tfstateãã¡ã€ã«ãšAWSäžã®ãªãœãŒã¹ãæ¯èŒããå·®åãããå Žåã®ã¿ãããã€ãå®è¡ãããããç¡é§ãªãããã€ãé²ãããšãã§ããŸãã ãªãœãŒã¹ã®APIã³ãŒã«é åºã¯TerraformåŽã§èªåçã«å¶åŸ¡ããããããã³ãŒãå
ã§ã®èšè¿°é åºãæ°ã«ããå¿
èŠã¯ãããŸããã 瀟å
ã»ç€Ÿå€ãšãã«ãã¬ããžãè±å¯ Terraformã¯ãããã£å
ã§5幎以äžåããå©çšãããŠãããå€ãã®ç€Ÿå¡ã䜿ãæ
£ããŠããããŒã«ã§ãããã®ããããã©ãã«ãçºçããéã瀟å
ã®çµéšè
ã«çžè«ããããšã§è§£æ±ºã§ããããšãå€ãã瀟å
ãã¡ã€ã³ã«æ²¿ã£ããã¹ããã©ã¯ãã£ã¹ãªã©ãæçãã€ã€ãããŸãã ãŸãã瀟å€ã§ãåºãå©çšãããŠãããããã€ã³ã¿ãŒãããäžã®æ
å ±ãè±å¯ã§ããã©ãã«ã·ã¥ãŒãã£ã³ã°ã容æã§ãã ã¢ãžã¥ãŒã«å岿©èœãäŸ¿å© ã¢ãžã¥ãŒã«ãåå©çšå¯èœãªåäœã«åå²ã§ããç°å¢äŸåã®èšå®ãå€åŽã«åé¢ããããšã§ãæ¬çªç°å¢ãšéçºç°å¢ã®ãããã€ãå¹ççã«ç®¡çã§ããŸãã ãµãŒããŒã¬ã¹ã¢ããªã®éçºã«ã¯åããŠããªã Terraformã¯ãµãŒããŒã¬ã¹ã¢ããªã±ãŒã·ã§ã³ã®ç®¡çãåŸæã§ã¯ãããŸãããç¹ã«Lambdaã«é¢ããŠã¯ã1ã€ã®é¢æ°ã«å¯ŸããŠå€ãã®ããããã£ãèšå®ããå¿
èŠãããããŸãããããã€ã«å¿
èŠãªzipãã¡ã€ã«ã®ãã«ãããã»ã¹ãè€éã«ãªããã¡ã§ãããã®ãããç§ãã¡ã®ããŒã ã§ã¯ãããã®èª²é¡ã«å¯ŸåŠããããã«AWS SAMãæ¡çšããŠããŸãã ã³ã©ã ïŒåç»çŽ¹ä» Terraformã®ã¡ãªããã«ã€ããŠããã£ãšè©³ããç¥ãããæ¹ã¯ããã¡ã®ã¡ã³ããŒãåããããã解説ããŠããTech talkã®åç»ããã§ãã¯ããŠã¿ãŠãã ããïŒ AWS SAM åçš®ããã±ãŒãžã®ç®¡çã容æ AWS SAM ã¯ãããã€åã«ãã«ãããã»ã¹ãå®è¡ããŸãããã®éã«å¿
èŠãªããã±ãŒãžã®ã€ã³ã¹ããŒã«ãšãããã€çšã®zipãã¡ã€ã«ã®äœæãèªåçã«è¡ãããŸãã ãã¡ãã®buildã¯ãªãã·ã§ã³ã§ã³ã³ããäžã§ãè¡ãããšãã§ãããããbuildç°å¢ã«äŸåããªãäœãã«ããããšãã§ããŸãã éçºæ©èœãè±å¯ ããŒã«ã«ç°å¢ã§ã®å®è¡ã»ãã¹ããå¯èœã§ãã³ã³ããããŒã¹ã®åäœã«ããç°å¢äŸåæ§ãæé€ã§ããŸãããŸããsyncãšãããªã¢ãŒãã®AWSäžãšããŒã«ã«ã®ã³ãŒããåæžããæ©èœãæèŒãããŠãããéçºå¹çãåäžãããããšãã§ããŸãã ããŒã éã§ã®ç®¡çã容æ CloudFormationãå©çšããŠç®¡çãããŠãããããtfstateãã¡ã€ã«ãšãã£ãäŸåé¢ä¿ç®¡çãã¡ã€ã«ãS3ã«ã¢ããããŒãããå¿
èŠããããŸããããŸãããªãœãŒã¹ã®åé€ãCLIã ãã§ãªããAWSã³ã³ãœãŒã«ããäžæ¬ã§è¡ãããšãã§ããŸãã å€§èŠæš¡ã¢ããªã±ãŒã·ã§ã³ã¯äžåã CloudFormationãããŒã¹ãšããŠãããããã¢ãžã¥ãŒã«åããŠåé¢ããããšãã»ãŒäžå¯èœãšãªã£ãŠããŸãããŸããYAML圢åŒã§æžãããŠãããããã³ãŒããåé·ã«ãªã£ãŠããŸããå¯èªæ§ãäœäžããããšãAWS SAMã®èª²é¡ã§ãã å®éã«éçšããŠã¿ãŠ ããŒã ã¡ã³ããŒããã®ææ³ãèããŠã¿ãŸããã ã³ã³ãœãŒã«ã§ã®äœæ¥æé ã®äœæãäžèŠã«ãªã£ãã®ã¯å¬ãã ãããã€æã¯IaCãéããªããã°ãããªãã®ã§ãå
šå¡ã倿Žå±¥æŽã远ããããã«ãªã£ã Git(GitHub)ã§ç®¡çã§ããããã«ãªã£ãã®ã§ãããŒãžã§ã³ç®¡çãã§ããããã«ãªã£ã ãããã€æã¯ç°å¢å·®åã®ã¿ã«éäžããã°ãããªã£ãã®ã§ãéåžžã«ãªãªãŒã¹æã®ãã¹ãæžã£ã AWS SAMã«é¢ããŠã¯ãå®è¡ãŸã§æå
ã®ãšãã£ã¿ã§å
šãŠå®çµããã®ã¯éçºäœéšãšããŠãã ãããã€ãé
ãã®ã§ãåŸ
ããªããã°ãããªãã®ã¯äžäŸ¿(lambdaã®ã³ããã¯çŽãã«ããã ã®ã§) 管çãæ¥œã«ãªããšåãããèããŠãããã©ãå®éã¯æã£ãŠããããæ¥œã§ã¯ãªãã£ã IaCãèªããããã«ãªããŸã§ã®åŠç¿ã³ã¹ããé«ã ã³ãŒãã§å
šãŠç®¡çã§ããããã°ã©ãã£ã«ã«ã«äŸåé¢ä¿ãèŠãããšãã§ããªãã®ã¯æ®å¿µ IaCã®å°å
¥ã«ãã£ãŠç®¡çå¹çã倿Žå±¥æŽã®è¿œè·¡ãåäžããäžæ¹ã§ãåŠç¿ã³ã¹ãããããã€æéãªã©ã®éçšé¢ã§ã®èª²é¡ãèŠããŠããŸããã ãŸãšã æ¬èšäºã§ã¯ããããã£ã®ãµãã·ã¹ããŒã ã«ãããIaCããŒã«ã®éžæãšéçšã«ã€ããŠç޹ä»ããŸãããTerraformã¯åªçæ§ã®æ
ä¿ãè±å¯ãªãã¬ããžãã¢ãžã¥ãŒã«å岿©èœãªã©ãå€§èŠæš¡ãªã€ã³ãã©ç®¡çã«é©ããŠããäžæ¹ãAWS SAMã¯ãµãŒããŒã¬ã¹ã¢ããªã±ãŒã·ã§ã³ã®éçºã«ç¹åããæ©èœãæäŸããŠããŸãã å®éã®éçšã§ã¯ã倿Žå±¥æŽã®è¿œè·¡ãããŒãžã§ã³ç®¡çãç°å¢å·®åã®ç®¡çã容æã«ãªããªã©ã®ã¡ãªããã確èªã§ããŸãããäžæ¹ã§ãåŠç¿ã³ã¹ãããããã€æéãå¯èŠåã®èª²é¡ãªã©ãæµ®ã圫ãã«ãªããŸããã ãããã®ããŒã«ãç®çã«å¿ããŠäœ¿ãåããããšã§ãããå¹ççãªã€ã³ãã©ç®¡çãå¯èœã«ãªã£ãŠããŸããä»åŸãéçºè
ã®å£°ã«è³ãåŸããªãããããè¯ãéçºç°å¢ã®æŽåãé²ããŠãããããšæããŸãã
忥ããé
å»ããŠãã¿ãŸããã12/1ãæ¥æå§ãŸãã§ããããšãå®å
šã«å¿ããŠããŸããã ãããã£ã§ã¹ã¯ã©ã ãšãã³ãžã§ãªã¹ããããŠãã西éã§ããæ¥åã§ã¯2ããŒã ã®ã¹ã¯ã©ã ãã¹ã¿ãŒãããŠããŸãã æè¿ãã·ãã¥ãšãŒã·ã§ãã«ãªãŒããŒã·ããã®æ¬ãèªãã§å®è·µããŠã¿ãã®ã§ãä»åã¯ã¹ã¯ã©ã ã«ããããªãŒããŒã·ããã«ã€ããŠã話ãããããšæããŸãã ã¹ã¯ã©ã ããŒã ã«ãªãŒããŒã¯äžèŠïŒ ãã¹ã¯ã©ã ãã¹ã¿ãŒã¯ããŒã ãªãŒããŒã§ã¯ãªãããã¹ã¯ã©ã ããŒã ã«ã¯äžäžé¢ä¿ããªãã®ã§ããããããªãŒããŒã¯ããªãããšãã話ãèããããšã¯ãªãã§ããããã ïŒã¹ã¯ã©ã ã¬ã€ãã«ã¯ãã¹ã¯ã©ã ãã¹ã¿ãŒã¯çã®ãªãŒããŒã§ããããšãæžãããŠãããæ··ä¹±ãããããããŸããããããã«ã€ããŠã¯åŸè¿°ããŸãïŒ ãªãŒããŒã£ãŠãªãã ããïŒ ãªãŒããŒãšèããŠã©ããªã€ã¡ãŒãžãæµ®ãã³ãŸããïŒ ç€ŸäŒäººãªãããŒã ãªãŒããŒãäžåžãåŠçã®é ãªãéšæŽ»ã®éšé·ãçåŸäŒé·ã身è¿ãªãªãŒããŒåã§ãããããæè¿ã§ã¯æ°ããç·ç倧è£ã®ãªãŒããŒã·ããã«ã泚ç®ãéãŸã£ãŠããŸãã ãããã«ããããªãŒããŒãšã¯ããŒã ããŽãŒã«ã«å°ãåããããçµç¹ã®æææ±ºå®ãè¡ãã人ãåŸããã€ããŠãããããªããããªã¹ã¿ãŒæ§ãã«ãªã¹ãæ§ãæã£ãŠãããããªã€ã¡ãŒãžããããŸãã ãããªçæ³çãªãªãŒããŒã«èªåããªããšèšããããå°ããŸããã身è¿ã«ããŠããããã©ãã»ã©é Œãããã§ãããããã¹ã¯ã©ã ã§ã¯ããã®ãããªãªãŒããŒããäžèŠããšããŠããããã§ã¯ãããŸããã ãªãŒããŒãšäŒŒããããªè©æžããšããŠããã¹ãããããŸãããã¹ãšããèšèã«ã¯ããµãããããã£ãŠæ€
åã«åº§ããæš©åšçã§ãããæç€ºã¯ãããçŽæ¥æã¯åãããªã人ãã®ãããªã€ã¡ãŒãžããããŸãã ãã®ããã¹ããšäžç·ã«åãã®ã¯ïŒããšããã¹ã«å¿é
ããŠãããšããŠãïŒæ¥œããããã¯èŠããããªã€ã¡ãŒãžããããŸãã äžæ¹ã§ããããé Œãã«ãªããªãŒããŒããšäžç·ã«åããããããå®å¿ããŠã幞ãã«åããããªã€ã¡ãŒãžãããã®ã§ã¯ãªãã§ããããã ã¹ã¯ã©ã ããŒã ã«ãã¹ã¯äžèŠã§ããããªãŒããŒã¯å¿
èŠã§ãã ããã«ãã¹ã¯ã©ã ããŒã ã®ãªãŒããŒã¯ã²ãšãã ãã§ã¯ãããŸããããªãŒããŒã·ãããçºæ®ã§ãã人ãããã°ããã»ã©ãããŒã ã®ã¢ãžãªãã£ãå¢ããŠããã®ã§ãã ãã®ãããŒã ã«ãªãŒããŒãããããããããšã¯ã©ããªç¶æ
ã§ããããã æè»ãªãªãŒããŒã·ããã¹ã¿ã€ã« èªåãã¹ã¯ã©ã ã«ããããªãŒããŒã·ããã«ã€ããŠæèããããã«ãªã£ãã®ã¯ã Regional Scrum Gathering Tokyo 2022 1æ¥ç®åºèª¿è¬æŒã«ãã£ãAgile Program Managementãšããã»ãã·ã§ã³ããã£ããã§ããã ãã®ã»ãã·ã§ã³ã§ãïŒã¹ã¯ã©ã ããŒã ã¯ïŒå
šå¡ããªãŒããŒã§ããããªãŒããŒãšãã©ãã¯ãŒãã·ãŒã³ã«ãã£ãŠåãæ¿ããããšãã話ãèããåå è
å士ã§ãªãŒããŒã·ããã®è§£éã«ã€ããŠããªãçãäžãã£ãèšæ¶ããããŸãã ãã®è©±ãèããåœåã¯ãå
šå¡ããªãŒããŒãšããç¶æ³ãã€ã¡ãŒãžã§ããŸããã§ãããå
šå¡ãæææ±ºå®è
ãšããç¶æ³ã§ã¯ãé²ããã®ãé²ã¿ãŸããããè¹é å€ãããŠè¹å±±ã«äžãããšãã諺ããããããæ®éçãªã¢ã³ããã¿ãŒã³ã§ãã ããã§å€§äºãªã®ã¯ãå
šå¡ããªãŒããŒãšããç¹ãããã ãªãŒããŒãšãã©ãã¯ãŒãã·ãŒã³ã«ãã£ãŠåãæ¿ãã ããšããç¹ã§ãã äŸãã°ãããã·ãŒã³ã§ã¯iOSãåŸæãªAããããªãŒãã£ã³ã°ããããå¥ã®ã·ãŒã³ã§ã¯AndroidãåŸæãªBããããªãŒãã£ã³ã°ãããšããç¶æ³ãæããŠããŸãã ãã®å ŽåãAãããBãããã©ã¡ãããªãŒããŒã·ãããçºæ®ããŠããŸããããããAãããBãããåžžã«ãªãŒããŒã§ã¯ãªãããäºããåŸæãªã·ãŒã³ããšã«ãªãŒããŒããµããŒãããåŽïŒãã©ãã¯ãŒïŒã«ãŸãã£ãŠããŸãã æè¡é å以å€ã§ãã説æãäžæãªCããã«ããŒã å€ãšã®äº€æžããé¡ãããããç²ŸåºŠãæ±ããããä»äºã¯ãã£ããã ã確å®ã«ä»äºãããªããŠãããDãããäžå¿ã«ãé¡ãããããããªã©ãæçããããŒã ã§ã¯ãã®äººã®ç¹æ§ãåŸæåéã«å¿ããŠèªç¶ãšå ŽããªãŒãã£ã³ã°ãã人ãå€ãã£ãŠãããŸãã ã·ãã¥ãšãŒã·ã§ãã«ãªãŒããŒã·ãããšããèãæ¹ åœæãã®ããªãŒããŒãšãã©ãã¯ãŒãã·ãŒã³ã«ãã£ãŠåãæ¿ããããšããèãæ¹ã«æéããããã®ã§ãããå
æ¥ååãããæ°1åéãªãŒããŒã·ãããšããæ¬ãè¯ãããšèããŠèªãã ãšããããã®ãæè»ãªãªãŒããŒã·ããã¹ã¿ã€ã«ãã«ã€ããŠããããããæžãããŠããã®ã§ç޹ä»ããŸãã 人ãã©ãããæé·éçšã«ãããã«ããããŠãçºæ®ãããªãŒããŒã·ãããå€ãã äŸãã°ç¹å®ã®åéãæªçµéšã®æ°å
¥ç€Ÿå¡ãšãçµéšæžã¿10幎ç®ã®ç€Ÿå¡ãåæã«ããŒã ã«ã¢ãµã€ã³ããããšãã«ãæ¥åã«å¯ŸããŠåãæãæ¹ãããã§ããããã 1幎ç®ã®ã¡ã³ããŒã«ã¯ãããããã§æããããšã«ãªãã§ããããã10幎ç®ã®ã¡ã³ããŒã«ã¯éã«ããã£ãšå¹ççãªããæ¹ã¯ãªããããšæããä¹ããããããŸããã ãã®ãããªåçŽãªäŸã ãšããããããã§ãããçŸå®ã¯ãã£ãšè€éã§ãã 察å¿è
ã®åéããšã®ç緎床ãšãªãŒããŒã®æ¥ãæ¹ããã¿ãããªããšããããã£ãŠããã®ã«çްããæç€ºãããŠããããããããããããªãã®ã«äœã®æç€ºããªãéæ¹ã«ãããããšãã£ãããŒã å
äžåãããŸããŸãã æèåããïŒã¢ã©ã€ã³ã¡ã³ãïŒå¯Ÿè©±ããã ãã®äººã®ç緎床ã®èªèãšãªãŒããŒã®æ¥ãæ¹ã§äžåãçãŸãªãããã«ããªãŒããŒã¯1on1ã®å Žã§ãã®èªèãåãããŸããã¹ã¯ã©ã ã®å Žåã¯ããŸãã¯ã¹ã¯ã©ã ãã¹ã¿ãŒãšããŒã ã¡ã³ããŒã§1on1ãããã®ãè¯ãã§ãããã èªåãæ1ã®é »åºŠã§ããŒã ã¡ã³ããŒãš1on1ãããŠããã®ã§ãå®éã«ä»¥äžã«ã€ããŠèããŠã¿ãŸããã æé·æ®µéã®èªèåãã ãæ°1åéãªãŒããŒã·ãããã®æ¬ã§ã¯ãä»äºã«ãããçºéã®éçšã以äžã®ããã«å®çŸ©ããŠããŸãã D1:ææ¬²æºã
ãªåå¿è
ã¡ã³ããŒã®ç¶æ
ïŒæèœãäœããææ¬²ãé«ã ä»äºã®ããã¯ããããªã«ãããããªãããæç€ºã«ã©ãã©ãåŸã£ãŠä»äºãèŠããããæ°ã«æºã¡æº¢ããŠããã ãªãŒããŒã®æ¥ãæ¹ïŒçްããå
·äœçã«æç€ºãåºããæç€ºåãã§æ¥ããããªãŒããŒãèªããã£ãŠã¿ããã·ãŒã³ãããã D2:æåŸ
ãå€ããåŠç¿è
ã¡ã³ããŒã®ç¶æ
ïŒæèœãäœãäžã§ãææ¬²ã¯äœã åŠç¿ãé²ãã§æèœã¯èº«ã«ã€ããŠããããããã«èŠããŠããé£ãããèªåã®æèœã®è¿œãã€ããªããªã©ã§ããæ°ãäœäžããŠãã ãªãŒããŒã®æ¥ãæ¹ïŒãæç€ºåããšãæ¯æŽåãã©ã¡ããè¡ããæç€ºã®èæ¯ã«ããæå³ã説æããã¡ã³ããŒã®æèŠãèããŠæææ±ºå®ã«å ããããä¿ãã D3:æ
éã«ãªããã¡ãªè²¢ç®è
ã¡ã³ããŒã®ç¶æ
ïŒæèœãäžãé«ã§ãææ¬²ã¯äžå®å® ã§ããããšãå¢ããŠããŠãä»äºã«å¯Ÿããææ¬²ãæ»ã£ãŠãããããããã²ãšãã§åããã»ã©ã®æèœã¯ãªãèªä¿¡ããã£ãŠåãçµããªãã ãªãŒããŒã®æ¥ãæ¹ïŒãæç€ºåãã¯å°ãªãããæ¯æŽåããå€ããã¡ã³ããŒãšãªãŒããŒå
±åã§æææ±ºå®ãè¡ãããªãŒããŒã¯èã圹ã«åã£ãŠã¢ã€ãã¢ãåŒãåºãã D4:èªç«ããéæè
ã¡ã³ããŒã®ç¶æ
ïŒæèœãé«ããææ¬²ãé«ã ãã®åéã«ãããŠã¯äœã§ãä»»ããïŒãšããç¶æ
ãèªä¿¡ãããã ãªãŒããŒã®æ¥ãæ¹ïŒæææ±ºå®ãå«ããŠãã®äººã«ä»»ããæç€ºã¯ããªãããã®äººã®è²¢ç®ãè©äŸ¡ããæé·ãå¿æŽããã ãã®ããã«ãåŠç¿æ®µéã«å¿ããŠãªãŒããŒã®æ¥ãæ¹ãå€ãããšããããšã説æããäžã§ãèªåãã©ã®æ®µéã«ãããããã¡ã³ããŒã«ç¢ºèªããŠããããŸãã æ¬æ¥ã¯ã¿ã¹ã¯ããšã«çްããèªèåãããããã»ããããã®ã§ããããŸãã¯ãä»èªåãããã¹ã¯ã©ã ããŒã ã®ä»äºã«ãããŠã©ã®ããããããšããç²åºŠããå§ããŸããã ãŸããã¹ã¯ã©ã ãã¹ã¿ãŒã®ç§ããèŠãŠã©ãèŠããŠããããšããããšãäŒããŠçžäºã«èªèåãããããŸããã èªåããžã§ã€ã³ããŠãã2ã€ã®ããŒã ã§ãã£ãŠã¿ããšãããçžäºã®èªèã¯ã»ãŒäžèŽããŠããŸãããããºã¬ãå Žåã¯æ¬äººãæãããç§ã®è©äŸ¡ã®æ¹ãé«ãæããŠããããšãå€ãã£ãã§ãã åºæ¬çã«ã¯ã¡ã³ããŒã®æèŠãéèŠããŸãããé床ã«äœãè©äŸ¡ããŠããããã§ããã°ãäºå®ã亀ããŠãã£ãšã§ããŠããããšãäŒããããšãè¡ããŸããã ãã1on1ã®ã³ãŒãåŽãæãããã¡ã³ããŒèªèº«ã®è©äŸ¡ãé«ã眮ããŠããå Žåã¯ãã¡ã³ããŒã®èªèãã®ãŸãŸã§ç®æšãç«ãŠãŠããããã§ããé«ãç®æšã«åããŠé 匵ãããšããã®ã§ãæ¬¡ç¬¬ã«æ¬åœã«ãã®è©äŸ¡ã«è¿œãã€ããšæ¬ã«ãããŸããã å
šå¡ããªãŒããŒã«ããªãããããŒã ãããã äžèšã®èªèåããã¯ãŸã 1åãã£ãã ããªã®ã§ãããã«ãã£ãŠå
·äœçã«ããŒã ãå€ãã£ããšããããšã¯çŸæ®µéã§ã¯èµ·ããŠããŸããããã ã1on1ã®å§ãŸãã®ãã§ãŒãºã§ä»åŸã䜿ã£ãŠãããããšæã£ãŠããŸãã èªåã®ç«ã¡äœçœ®ã瀺ããã®ãšããŠããããããããšããããŸãããå人çã«ã¯ããŸãã¯ãã®ãããªèãæ¹ãéããŠãå¯å€ãããªãŒããŒã·ããã®ããæ¹ãã¡ã³ããŒã«äŒããŠããããšã倧äºã ãšèããŠããããã§ãã åé ã«ãã¹ã¯ã©ã ããŒã ã«ãªãŒããŒã¯äžèŠïŒããšæžããŸããããã¹ã¯ã©ã ããŒã ã«ã¯ããã¹ãåºå®ã®ãªãŒããŒã¯äžèŠã§ããã·ãŒã³ã«å¿ããŠèª°ã§ããªãŒããŒã®åžœåã被ããããã«ããŸãã ããã¯ãã¹ã¯ã©ã ãã¹ã¿ãŒã¯çã®ãªãŒããŒã§ããããšããã¹ã¯ã©ã ã¬ã€ãã®èšèãšãççŸã¯ããŸãããç§ã¯ãã®èšèããã¹ã¯ã©ã ãã¹ã¿ãŒã¯ãããŒã ãçµç¹ã®ããæ¹ãè¯ãã§ããããªãã©ã€ã¢ã³ããšã©ãŒã 誰ãããçå
ããŠè¡ã ãšããæå³ã§æããŠããŸãã äŸãã°ãã·ãã¥ãšãŒã·ã§ãã«ãªãŒããŒã·ãããã¹ã¯ã©ã ãã¹ã¿ãŒãçå
ããŠå®æœãããããèŠãŠããŒã ã¡ã³ããŒããªãŒããŒã·ãããçºæ®ããŠããããšããããããã¯ã¹ã¯ã©ã ãã¹ã¿ãŒãçã«ããŒã ããªãŒãã£ã³ã°ããŠããç¶æ
ãšãããã®ã§ã¯ãªãã§ããããã ãªãŒããŒãšã¯ããã®åã®éãå
é ã«ç«ã£ãŠãã®ãåŒã£åŒµã人ã§ãããã£ãšäžäººã§ãã£ãŠãããç²ããŠããŸããããã©ãã¯ãŒãäžäººã®èäžãèŠãŠåŠã¹ãããšã¯éãããŠããŸããŸãã ã·ãŒã³ã«å¿ããŠè²ã
ãªäººããªãŒãã£ã³ã°ã§ããã°ãè²ã
ãªäººã®èäžãèŠãŠåŠã³ããã£ãšå¢ããããšãã§ããŸãããŸããèªåããªãŒãã£ã³ã°ããŠãããšãããåŸãã«ã¯ãªãŒããŒã«ãªããããã匷åãªãã©ãã¯ãŒãã€ããŠãããšããå®å¿æããããŸãã ã¹ã¯ã©ã ããŒã ã¯æ±ºããŠãªãŒããŒãäžåšãªããŒã ã§ã¯ãããŸãããã·ãŒã³ã«å¿ããŠèª°ã§ããªãŒããŒã®åžœåã被ãããšãã§ããããŒã ãªã®ã§ãã ã·ãã¥ãšãŒã·ã§ãã«ãªãŒããŒã·ãããšããèãæ¹ã¯ãèªåŸçãªããŒã ãè²ãããã«è¯ãè¶³æããã«ãªããšæããŸãã ã¹ã¯ã©ã ã«ããããªãŒããŒã·ããã®ããæ¹ãäŒããããã«ã1on1ãªã©ã®ã·ãŒã³ã§ãã·ãã¥ãšãŒã·ã§ãã«ãªãŒããŒã·ããã®èª¬æãšãäºãã®ãæé·æ®µéã®èªèåãããã«ãã²ãã©ã€ããŠã¿ãŠãã ããã
ãã®èšäºã¯ã ãããã£ã°ã«ãŒã Advent Calendar 2024 3æ¥ç®ã®èšäºã§ãïŒ 2æ¥ç¶ããŠã®æçš¿ã«ãªããŸãã ã¯ããã« Azure ã AWS ãšåããä»®æ³ãããã¯ãŒã¯ã®ãµãããããã€ããããšãã§ããŸãã ä»åã¯ããã€ãã©ããããã®CIDRã§äœæããã°ããã®ãããããªããªãã®ã§ãå°ãèå¯ããŠã¿ããšãã®èšé²ãã玹ä»ããŸãã ã·ã¹ãã çãªæå°å€ ãµãããã ãµããŒããããæå°ã® IPv4 ãµãããã㯠/29ãæå€§ã¯ /2 ã§ãã Azure Virtual Network ã«é¢ãã FAQ ãµããããèªäœã®å¶éãšããŠãäžèšã®ã«ãŒã«ããããŸãã AWSã®ãµãããã㯠/28 ãŸã§ãªã®ã§ãããªã现ããåå²ã§ããŸããã ãã®ä»ã®ãµãŒãã¹ Azureã«ã¯ ãµããããã®å§ä»» ãšããä»çµã¿ããããŸãã Azure ä»®æ³ãããã¯ãŒã¯ã§ã®ãµããããã®å§ä»»ãšã¯ ããã¯ãç¹å®ã®Azure PaaSãµãŒãã¹ã§ãµãããããå æããä»çµã¿ã§ãããAzure Database for MySQL ãªã©ããã©ã€ããŒããªãããã¯ãŒã¯äžã«æ§ç¯ããããšããªã©ã«äœ¿çšããŸãã å¯ããè¯ãæ¹ã¯æ°ã¥ãããããããŸããããå®ã¯PaaSãµãŒãã¹ããšã«å§ä»»ããããµããããã®å€§ããã«å¶éãããã£ãŠããŸãã ãµãŒãã¹å æå° æå€§ åè åè Azure App Service /28 /26(1ã€ã®ãã«ãããã³ãã®æå€§ã¹ã±ãŒã«æ°) MPSJ ãå©çšããå Žå㯠/26 ãæå° https://learn.microsoft.com/ja-jp/azure/app-service/overview-vnet-integration Azure Database for MySQL /29 äžæ https://learn.microsoft.com/ja-jp/azure/mysql/flexible-server/concepts-networking-vnet ã·ã¹ãã ã«äºçŽãããIP ãµãããããäœæããæããµããããã«å²ãåœãŠãIPããã¹ãŠäœ¿ããããã§ã¯ãããŸãããå
é ãšæ«å°Ÿã®ã¢ãã¬ã¹ã¯ãããããããã¯ãŒã¯ã¢ãã¬ã¹ãšãããŒããã£ã¹ãã¢ãã¬ã¹ãšããŠäºçŽãããŸãããŸããAzureã¯1ã€ã®ãµããããã«ã€ã3ã€ã®ã¢ãã¬ã¹ãã·ã¹ãã çã«äºçŽããŸãã ãã®ãããæçµçã«å©çšå¯èœãªIPã¯ã ãµããããã®IPCIDRãã5ã¢ãã¬ã¹é€ããIPã«ãªããŸãã Azure Virtual Network ã«é¢ãã FAQ éçšã«æ²¿ã£ãæå°å€ãèå¯ IPå¶éãããšããããšã¯ãããã ãã¹ã±ãŒãªã³ã°ã®å¹
ãçããããšãšãªããŸãããŸããä»®æ³ãããã¯ãŒã¯ãåå²ãããããšç®¡çããããšã倧å€ã§ãããã®ããAzureã§ã¯ VNetã¯å€§ãããSubnetã¯å°ããäœãããšãæšå¥šãããŠããŸãã Azure Virtual Network ã«é¢ãã FAQ ããããªãããåŒç€Ÿã®ãããã¯ãŒã¯æ§æã®å¶çŽäžãVNetã¯å€§ããäœæããããšãã§ããŸããã ã§ã¯ãã©ããããã®CIDRãçŸå®çãªèšå®å€ãªã®ã§ããããïŒ 1ã€ã®VNetãå æããã¢ããªã±ãŒã·ã§ã³ã®å Žå ãããã1ã€ã®VNetã1ã€ã®ã¢ããªã±ãŒã·ã§ã³ã§å æããããšã«ãªããšæããŸãã å©çšãããµãŒãã¹ã«ããããŸãããæäœã§ã /26 ã®VNetãçšæããŠã4ã€ä»¥äž( /28 )ã«åå²ããŠäœ¿ãããã§ãã ããå€§èŠæš¡ãªå Žåã¯ã /24 ã§æãåºããããã§8ã€ä»¥äž( /27 )ã«åå²ããŠäœ¿ãããšå®å®ããŠéçšãã§ãããã§ãã 1ã€ã®VNetã«è€æ°ã®ã¢ããªã±ãŒã·ã§ã³ãããã®ãããå Žå ãã¡ãã¯ããã®ãããã¢ããªã±ãŒã·ã§ã³ã®æ°ã«ãããŸãã 4ã€ã»ã©ãªããæäœã§ã /26 ã®VNetãçšæããŠã4ã€ä»¥äž( /28 )ã«åå²ã§è¶³ãããšæããŸãã ãã以äžã¯ã4ã€ã»ã©ãªããæäœã§ã /25 ã®VNetãçšæããŠã8ã€ä»¥äž( /28 )ã«åå²ã§è¶³ãããšæããŸãã å°ããã¢ããªã±ãŒã·ã§ã³ã ãšæãã®ã§ã1ã€ã®ãµãããã㯠/28 ã§ååè³ãããšæããŸãã ãŸãšã æ¬èšäºã§ã¯ããµããããã®èšå®ããããšãã®èå¯ãæžããŸããã IPå¶éãããŠããç°å¢ãšéä¿¡ãããå Žåã¯é©åã«subnetãäœæããŠç®¡çããŠãããã§ããã
ãã®èšäºã¯ microCMSã§ãããªããšãã§ããïŒããªãã®ãŠãŒã¹ã±ãŒã¹ã倧åé by microCMS Advent Calendar 2024 3æ¥ç®ã®èšäºã§ãã ã¯ããã« ããã«ã¡ã¯ããããã£æ ªåŒäŒç€Ÿã®å®®æ¬ã§ãã ä»åã¯microCMSã®ã¢ããã³ãã«ã¬ã³ããŒåå èšäºãªã®ã§ãåããŠNIFTY engineeringãé²èЧããæ¹ãå€ããšæããŸãã ãããã£ã§ãmicroCMSãå©çšããŠè€æ°ã®ãµã€ããéçšãããŠããããã£ãããªã®ã§ä»åã®ã¢ããã³ãã«ã¬ã³ããŒã«åå ãããŠããã ããŸããã ã³ã³ãã³ãã®å
容ã«ãã£ãŠéç¥å
ãå€ããã microCMSã«ã¯ãã³ã³ãã³ãã®å€æŽããã£ãéã«å©ãããšã®ã§ããWebhookæ©èœããããŸããããã©ã«ãæ©èœãšããŠãSlackãžã®éç¥ãäž»èŠãªãã¹ãã£ã³ã°ãµãŒãã¹ã®ãã«ãçšWebhookãçšæãããŠããŸãããã«ããéç¥ãã³ã³ãã³ãã®æŽæ°æã«å®æœãããã®ã§ãæ¬ ãããªãæ©èœã§ããã ããŠãæ¬é¡ã§ããèªåãè§Šã£ãŠããAPIã®äžã«ã¯ãã³ã³ãã³ãã®å
容ã«ãã£ãŠå©ãããWebhookãå€ããAPIããããŸããããšãã°ãç¥ããAPIã§ãããç¥ããã®çš®é¡ã«ãã£ãŠå¥ã®Slackã«éç¥ãããããªã©ã§ããããŸãèãããã¯ãªãã§ãããé害é¢é£ã®ãç¥ããã¯é害çšã®ãã£ã³ãã«ã«ãæµããªã©âŠâŠã ãã®ãšããmicroCMSã®ããã©ã«ãã®Webhookã ãšãWebhookãå©ãã³ã³ãã³ãã®æŽæ°ã¿ã€ãã³ã°èªäœã现ããã«ã¹ã¿ãã€ãºããããšã¯ã§ããŠããã³ã³ãã³ãå
容ã«ãã£ãŠå©ãWebhookãæ±ºããããšã¯ã§ããŸããã ããã解決ããããšããå Žåãã«ã¹ã¿ã Webhookã䜿ã£ãäžã§åŠçå
容ã«ãã£ãŠåå²ããAPIãäœæããå¿
èŠããããŸããå®çŸããæ¹æ³ã®äžäŸãšããŠAPI Gateway + LambdaãæããããŸããããããããããç«ãŠãã®ã¯çµæ§é¢åã§ãããšãããé¢åã§ãããå¥ä»¶ã§ããè€éãªåŠçããããã«APIãããããäœæãããã§ãããcdkã§API Gatewayã建ãŠãã®ãå°å³ã«é¢åãããâŠâŠãã§ããã°ããã£ãšç°¡åãªæ¹æ³ã§å®çŸãããã§ãã ããã§ãZapierãçšããŠWebhookã®å©ãå
ãæè»ã«ã«ã¹ã¿ãã€ãºããæ¹æ³ã玹ä»ããŸãã Zapier Zapier ã¯ããŒã³ãŒãã§ã¯ãŒã¯ãããŒãäœæã§ããiPaaSã§ããä»ã®æ§ã
ãªSaaSãšçµã¿åãããããšã§ãããããªããšãã§ãã瀟å
ã§ã ããŸããŸãªå Žé¢ ã§å©çšãããŠããŸãã ãªããä»åæ±ãWebhookæ©èœã¯ææãã©ã³ã§ãªããã°å©çšã§ããªããããæ³šæãã ããã microCMSã®æŽæ°ãZapierã§åãåã£ãŠéç¥ãã microCMSåŽã§ãç¥ããã®çš®é¡ãã»ã¬ã¯ãããã¯ã¹ã§éžã¹ãããã«ããæ¬¡ã®ãããªã¹ããŒãã®APIã§èããŸãã ããããç¥ããã®çš®é¡ã«åãããŠSlackéç¥ããã«ã¯ã以äžã®ãããªæé ãå¿
èŠã§ãã Zapierã®Webhookãèµ·ç¹ã«microCMSããã®ããŒã¿ãååŸ ã³ã³ãã³ãã®çš®é¡ã«å¿ããå©ãããWebhookãååŸ éç¥çšã®Webhookãå©ã Zapierã®Webhookãèµ·ç¹ã«microCMSããã®ããŒã¿ãååŸ Zapierã§æäŸãããŠããWebhook Appãããªã¬ãŒã«ããããšã§ãååŸèªäœã¯ã§ããããã«ãªããŸãããã®æç¹ã§Webhookãå©ããã¹ããå®è¡ãã§ããã®ã§ãmicroCMSã®ã«ã¹ã¿ã Webbhookã«ZapieråŽã§çºè¡ãããWebhookãæå®ãããšãå®éã«åäœããéã®è¿åŽå€ã確èªã§ããŸãã è¿åŽå€ã¯ä»¥äžã®ãã確èªã§ããŸãïŒã ãã¶é·ãã®ã§äžéšæç²ïŒã å«ãŸããããŒã¿ã¯ microCMSã®å
¬åŒããã¥ã¡ã³ã ãã確èªã§ããŸãã ãã®ãšããæ°èŠäœæã»å
¬éã»äžæžã远å ã»å
¬éããç¶æ
ã§ã®äžæžã远å ã»åé€çã
ãçºç«æã®æäœã«ãã£ãŠå«ãŸããã³ã³ãã³ãã®ããŒã¿ã®éãããç°ãªãããæ³šæãå¿
èŠã§ãããŸãããã®åŸã®ã¹ãããã§åç
§ãããå€ã¯ãã¹ãæã®ãªã¯ãšã¹ãã«å«ãŸããŠããå¿
èŠããããŸãã äžæžããååšããå
¬éæžã¿ã®ã³ã³ãã³ãã®äžæžããæŽæ°ããæäœã§Webhookãçºç«ãããŠãããšãã²ãšãŸãå
šéšèŒãã®ããŒã¿ãåããã¯ãã§ãã éç¥å
ãååŸ Zapierã«ã¯åŠçãåå²ãããPath Appããããããã䜿ããšç°¡åã«åå²åŠçãåå²ã§ããŸããããããåå²äžéãããã©ã«ã5ä»¶ãšæ±ºãŸã£ãŠããŸããäžéãå¢ããããšãã§ããããã§ãããããããã䟿å©ãªæ¹æ³ããããŸãã ãããããGoogle ã¹ãã¬ããã·ãŒããZapier Tableã«ã³ã³ãã³ãã®å
容ãšå©ãããWebhookã®URLãèšå
¥ããŠããã°ãã³ã³ãã³ãã®å
容ããæ€çŽ¢ããŠå¯Ÿå¿ããè¡ã®æ
å ±ãååŸããããšãã§ããŸãã ãããªæãã®ã¹ãã¬ããã·ãŒããçšæã㊠ã³ã³ãã³ãã®ã¹ããŒã¿ã¹ãããšã«æ€çŽ¢ããããã«ããã° ZapieråŽã§è©²åœã®è¡ãååŸã§ããŸãã ååŸããWebhookãå©ã æåŸã¯ç°¡åã§ãããããWebhook Appã䜿ã£ãŠãåã®ã¹ãããã§ååŸããURLã«åããŠãªã¯ãšã¹ããæããã ãã§ããã ãŸããéç¥å
容ãç·šéã§ããããã³ã³ãã³ãã®å
容ãå«ããéç¥ã«ããããšãå¯èœã§ãã Headerãªã©ãèªç±ã«æå®ã§ãããããåãªãSlackéç¥ä»¥å€ã«ããèªèšŒãå¿
èŠãªWebhookãå©ãããšãã§ããŸãããã®éã¯ããŒã¿ãååŸããWebhookããŸãšããã¹ãã¬ããã·ãŒããªã©ã«ãèªèšŒæ
å ±ã®è¡ãªã©ã远å ããŠåç
§ã§ããããã«ããŠãããšäŸ¿å©ã§ãã æåŸã« microCMSãšZapierãçµã¿åãããããšã§ãã³ã³ãã³ãã®æŽæ°ã®çš®é¡ã ãã§ãªãã³ã³ãã³ãã®å
容ã«å¿ããŠãéç¥å
ãæè»ã«å€æŽããããšãã§ããŸããSlackãžã®éç¥æèšã«æŽæ°å
容ãå«ãŸããã ãã§ã䟿å©ãããããŸãããéç¥ã®äœæèªäœããšãŠãç°¡åãªã®ãå¬ããã§ããä»å玹ä»ããZapãããã£ã3ã¹ãããã§ã§ããŠããŸãã ãŸãã䜿ãããã«ãã£ãŠã¯Slackéç¥ä»¥å€ã«ããããªãæè»ã«å¥ã®SaaSãžã®é£æºãªã©ãä»èŸŒãããšãã§ããŸãã äžæ¹ã§Zapierã«ãéçã¯ãããããè€éãªããšããã¯ã©ãŠããªãœãŒã¹ã«å¯ŸããŠäœãããããšããå Žåã¯API Gateway + Lambdaã®ãããªæ§æãäœãå¿
èŠããããšæããŸãããã®èŸºãã«ã€ããŠã¯ãäºåã«äœããããããã£ããèããå¿
èŠããããŸããããšããããZapierã§åãã詊ããŠã¿ãããšãç°¡åã«ã§ããããšãé
åã®äžã€ã ãšæããŸããmicroCMSèªäœãšãŠã䜿ããããã®ã§ãæ¥ã
ã®éçšãããå¿«é©ãªãã®ã«ããããã«ãããããããšå·¥å€«ã®ãããããããŸããã åè Automate without limits | Zapier ã³ã³ãã³ãã®Webhookãèšå®ïœmicroCMSããã¥ã¡ã³ã Paths – limited to 5? | Zapier Community
ç®æ¬¡ ã¯ããã« dbt Coreã®EOLããŒãžã§ã³ãµããŒãã«ã€ã㊠dbt Coreãã¢ããã°ã¬ãŒããããšãã®æšå¥šäºé
ç°å¢ã«ã€ã㊠[åå] ãšã©ãŒã®è§£æ±º [åŸå] 解決ã«è³ããŸã§ã®ããã»ã¹ ã¯ããã« ããŒã¿åºç€ããŒã ã®é¹¿éã§ãã ããŒã¿åºç€ããŒã ã§ã¯ãœãŒã¹ããŒã¿ã®ããŒã¿å€æåŠçãåã³ããŒã¿ã¢ãã«ã®ç®¡ççšéã§Data build toolã®OSSãªãªãŒã¹ dbt Coreãå©çšããŠããŸãã æ¬èšäºã§ã¯ãdbt Core 1.5ãžã®ã¢ããã°ã¬ãŒãæã«çŽé¢ãããšã©ãŒã«ã€ããŠããã®è§£æ±ºçã解決ãŸã§ã®ããã»ã¹ããããŠåŸãããæèšãå
±æããŸãã æ¬èšäºã®ã¡ã€ã³éšåã¯ååã»åŸåã«åãããŠããŸãã ååã¯1ã2åã§èªããå
容ã§ããåæ§ã®ãšã©ãŒã§ãå°ãã®æ¹ã¯ããŸãååãã芧ãã ããã dbt Coreã®EOLããŒãžã§ã³ãµããŒãã«ã€ã㊠dbt Coreã®EOLããŒãžã§ã³ãµããŒãã¯ãã®ãã€ããŒããŒãžã§ã³ã®ãªãªãŒã¹æ¥ãã1幎éãšå®ããããŠããŸãã 1 ãµããŒãæéãçµäºãããšãã»ãã¥ãªãã£ããããšããã¥ã¡ã³ãã®æäŸãçµäºããŸãã ãŸãæ°æ©èœãå©çšã§ããªããªããããç¹å¥ãªçç±ããªãéãã¯å®æçãªã¢ããã°ã¬ãŒã察å¿ãæšå¥šãããŸãã dbt Coreãã¢ããã°ã¬ãŒããããšãã®æšå¥šäºé
ã¢ããã°ã¬ãŒã察象ã®ããŒãžã§ã³ã¯ãçŸåšã®ãã€ããŒããŒãžã§ã³ãã1ã€ãŸãã¯2ã€ã®ç¯å²å
ã«çããããš ããã¯OSSã¢ããã°ã¬ãŒãã«éããã倿Žã«ãããªã¹ã¯ãæå°éã«æãããã ã¢ããã°ã¬ãŒããšé¢ä¿ã®ãªãä¿®æ£ã¯é¿ããããš æ°æ©èœã®è¿œå ãæ¢åã®æå倿Žã§ãªãã¡ã¯ã¿ãªã³ã°ããããªã£ãŠããããã¯åŸåãã«ããããš ç°å¢ã«ã€ã㊠dbt Coreã¯Amazon RedshiftããŒã¿ãã©ãããã©ãŒã ã«æ¥ç¶ããããšãåæãšããŠããŸãã dbt CoreããŒãžã§ã³ dbt Redshiftã¢ããã¿ãŒããŒãžã§ã³ å®è¡ç°å¢ 1.4.9 1.4.1 ã³ã³ããïŒPython 3.9 slimã€ã¡ãŒãžããŒã¹ïŒ Github Actions ãã¹ãããã©ã³ããŒïŒubuntu-latestïŒ [åå] ãšã©ãŒã®è§£æ±º ãšã©ãŒã®èª¬æãšè£è¶³ ééããè€æ°ã®ãšã©ãŒã®äžãããç¹ã«è§£æ±ºã«æéãèŠãã1ã€ãåãäžããŸãã dbt runå®è¡äžã«çºçãããšã©ãŒã§ãã¹ã¿ãã¯ãã¬ãŒã¹ã¯æ®ã£ãŠããªãããæåæ
å ±ã®ã¿ã§ãã Connection reset by peer èŠèŠãã®ããæ¹ãå€ãã®ã§ã¯ãªãã§ããããã ããã¯dbt Coreåºæã®ãšã©ãŒã§ã¯ãªãããããã¯ãŒã¯ã¹ã¿ãã¯ïŒTCPã¬ã€ã€ãŒïŒã«èµ·å ãããšã©ãŒã§ãã 以äžã«è£è¶³ãèšèŒããŸãã 調æ»ã®éçšã§å€æããã®ã§ããããã®ãšã©ãŒã¯Github Actionsãã¹ãããã©ã³ããŒç°å¢ã§ã®ã¿çºçããŠããŸããã ã©ããã£ãŠè§£æ±ºãããïŒ A. å®è¡ç°å¢ãGithub Actionsãã¹ãããã©ã³ããŒããã»ã«ããã¹ãããã©ã³ããŒãžç§»è¡ããŸããã å
·äœçã«ã¯ãGithubå
¬åŒãæäŸããubuntu-latestã©ã³ããŒãããEKSã¯ã©ã¹ã¿ãŒäžã®m5.largeã¿ã€ãã®ã¯ãŒã«ãŒããŒãäžã®ã©ã³ããŒïŒãããïŒãžç§»è¡ããããšã§è§£æ±ºããŸããã è£è¶³ã§æ¢ã«çãã瀺åããŠããŸãããç¹å®ç°å¢ã§ã®ã¿çºçããåé¡ã ãšå€æãããããå®è¡ç°å¢ã®å€æŽã§è§£æ±ºãå³ããŸããã å
å®¹ãæ·±ããããã以éã®ã»ã¯ã·ã§ã³ã§è£è¶³èª¬æãå ããŸãã Github Actions ã»ã«ããã¹ãããã©ã³ããŒç°å¢ã«ã€ã㊠æ£åŒå称㯠self-hosted runner ã§ãã åŒç€Ÿã§ã¯ãdbtã¢ãã«ãå®å
šã«æ¬çªç°å¢ãžå
¬éããããã®CIãGithub Actionsã§æ§ç¯ããŠããŸããïŒä»¥éãCIã¯ãŒã¯ãããŒãšåŒã³ãŸãïŒã CIã¯ãŒã¯ãããŒã§ã¯ãGithubå
¬åŒãæäŸããubuntu-latestã©ã³ããŒã䜿çšããŠããŸãããããããèªåã§çšæããã©ã³ããŒã«åãæ¿ããŸããã Github Actions ã»ã«ããã¹ãããã©ã³ããŒã®èæ
®äºé
ã»ã«ããã¹ãããã©ã³ããŒç°å¢ã®æ§ç¯èªäœã¯å
¬åŒããã¥ã¡ã³ãã«åŸãã°å®¹æã§ãããéçšé¢ã§ã¯ä»¥äžã®æžå¿µäºé
ãèæ
®ããå¿
èŠããããŸãã ã©ã³ããŒãå®è¡ãããã·ã³ãã©ããããïŒ ãã·ã³ã®ã¡ã³ããã³ã¹ ãã·ã³ã®ã»ãã¥ãªãã£æ
ä¿ Githubãã¹ãããã©ã³ããŒã§ã¯ãããã®æžå¿µäºé
ã¯GithubåŽã察å¿ããŠãããŸãããã»ã«ããã¹ãããã©ã³ããŒã¯ååã®éãå®è¡ç°å¢ãèªå·±ç®¡çããå¿
èŠããããŸãã ãã®ã»ã¯ã·ã§ã³ã§ã¯çµè«ã®ã¿èšèŒããŸããã Actions Runner Controller (ARC) ã®å°å
¥ã§ãããã®èª²é¡ã解決ããŸããã 詳现ãªããã»ã¹ã¯åŸåã§èª¬æããŸãã [åŸå] 解決ã«è³ããŸã§ã®ããã»ã¹ ååã¯å座ã§ãåŸåãã¡ã€ã³ã§ãã ãã ãããã¡ãã¯äž»ã«çµç·¯ã詳ãã説æããå
容ãšãªããããæç« éãå€ããªãããã詳现ãªèšè¿°ãšãªããŸãã ãçè§£ããã ããæ¹ãããé²ã¿ãã ããã 以äžã«ã解決ãŸã§ã®ããã»ã¹ãæç³»åé ã«èšèŒããŸãã åã¹ãããã«ã€ããŠè£è¶³ãå ããæåŸã«åŸãããç¥èŠããŸãšããŸãã 解決ãŸã§ã®ããã»ã¹ãæç³»åé ã«åæããŸããã ããããã®ã»ã¯ã·ã§ã³ã§è£è¶³ãããæåŸã«æ°ã¥ãããŸãšããŸãã dbt Coreã1.5ã«ã¢ããã°ã¬ãŒã dbt run ã§ãšã©ãŒçºç Redshiftã¯ã©ã¹ã¿ãŒã®ã¢ãã¿ãªã³ã°ããŒã¿ãããã³ãšã©ãŒãã°ã®ç¢ºèª dbt-redshiftã¢ããã¿ãŒèšå®ã®èŠçŽã Redshiftã¢ããã¿ãŒã®CHANGELOGç¢ºèª é¡äŒŒã®äºè±¡æ¢çŽ¢ã»èª¿æ» ä»åŸã®é²ãæ¹ã決ãã Github Actions ã»ã«ããã¹ãããã©ã³ããŒã§CIã¯ãŒã¯ãããŒæ€èšŒ Github Actions ã»ã«ããã¹ãããã©ã³ããŒç°å¢ã®éžå® ãŸãšã dbt Coreã1.5ã«ã¢ããã°ã¬ãŒã dbt Coreã¯pipã§ã€ã³ã¹ããŒã«ãããŠããŸãã 1.5ãžã®ã¢ããã°ã¬ãŒããšæžããŠããŸããã1.8ããåã®ããŒãžã§ã³ã§ã¯ãdbt CoreèªäœãçŽæ¥ã€ã³ã¹ããŒã«ããã®ã§ã¯ãªããåããŒã¿ããŒã¹çšã®ã¢ããã¿ãŒãã€ã³ã¹ããŒã«ããããšãæšå¥šãããŠããŸãã dbt Coreã¯ãã€ã³ã¹ããŒã«ããã¢ããã¿ãŒã®äŸåé¢ä¿ãšããŠèªåçã«ã€ã³ã¹ããŒã«ãããŸãã pip install dbt-redshift==1.5.11 ãã®æç¹ã§ã¯ãã¢ããã¿ãŒã®ããŒãžã§ã³1.5.11ãã€ã³ã¹ããŒã«ããŠããŸããã ããã¯åã«ææ°ã®ãããããŒãžã§ã³ãèŠèœãšããŠããããã§ãã dbt run ã§ãšã©ãŒçºç Github Actionsãã¹ãããã©ã³ããŒç°å¢ã§å®è¡ãããCIã¯ãŒã¯ãããŒã®dbt runã¹ãããã«ãããŠããConnection reset by peerããšã©ãŒãçºçããŸããã ãã®ãšã©ãŒã¯ãå®è¡ã³ã¹ãã®é«ãäžéšã®ã¢ãã«ã§ã®ã¿çºçããããšã倿ããŸããã ãããããã®æ®µéã§ã¯å®è¡ç°å¢ã®éãããšã©ãŒã®çºçã«é¢ä¿ããŠãããšããå¯èœæ§ã«æ°ã¥ããŠããŸããã§ããã Redshiftã¯ã©ã¹ã¿ãŒã®ã¢ãã¿ãªã³ã°ããŒã¿ãããã³ãšã©ãŒãã°ã®ç¢ºèª Redshiftã¯ã©ã¹ã¿ãŒã¯ãµãŒããŒã¬ã¹ã§ã¯ãªãRA3ã€ã³ã¹ã¿ã³ã¹ã®ããŒãã§æ§æãããŠããŸãã å®è¡ã³ã¹ãã®é«ãã¢ãã«ã§ã®ã¿ãšã©ãŒãçºçããŠãããããRedshiftã¯ã©ã¹ã¿ãŒã«è² è·ãããã£ãŠããã®ã§ã¯ãªãããšèããã¢ãã¿ãªã³ã°ããŒã¿ãšãšã©ãŒãã°ã確èªããŸããã ãã·ã³ãªãœãŒã¹ïŒCPUã»ã¡ã¢ãªïŒ ã¢ã¯ãã£ãæ¥ç¶æ° ã¯ãšãªã®åæå®è¡æ° ãã¥ãŒã«å
¥ã£ãã¯ãšãªæ°ãšåŠçãããã¯ãšãªæ°ã®çµ±èš ãšã©ãŒãã°ã«ã¯ç¹ã«ç®ç«ã£ãåé¡ã¯èŠããããæ¥ç¶æ°ãåæå®è¡æ°ãã¯ãšãªçµ±èšã®ããããã¯ã©ãŒã¿ã«ã¯éããŠããŸããã§ããã CPUã®äœ¿çšçã¯é«æ¢ãŸãããŠãããããã¹ããã¯ã¢ããã§è§£æ±ºã§ããå¯èœæ§ã¯ãããŸãããããŸãã¯ä»ã®è§£æ±ºæ¹æ³ãæ¢ãããšã«ããŸããã dbt-redshiftã¢ããã¿ãŒèšå®ã®èŠçŽã ã¯ã©ã€ã¢ã³ãåŽã§è² è·ã軜æžã§ããªãããšãã芳ç¹ããã¢ããã¿ãŒèšå®ãèŠçŽãããšã«ããŸããã 1.5ã§éæšå¥šãšãªã£ãèšå®é
ç®ãããã€ãèŠã€ãããŸãããããããã¯äžæŠä¿çãšããŸããã threads: 8 -> 4 -> 2 connect_timeout: 30 -> None read operation timed out ãIssueã«ãã£ãã®ã§ããã§åæå¯Ÿå¿ sslmode: prefer -> disable keepalives_idle: éæšå¥šãšãªã£ãã®ã§åé€ threadsã®èª¿æŽã«ããäžéšã®ã¢ãã«ã§ã¯åé¡ãè§£æ¶ãããŸããããããåŠçã³ã¹ãã®é«ãã¢ãã«ã«ã€ããŠã¯äŸç¶ãšããŠãšã©ãŒãçºçããŸããã ãã®ä»ã®ãã©ã¡ãŒã¿å€æŽã§ã¯ç®ç«ã£ã广ã¯åŸãããŸããã§ããã keepalives_idleãéæšå¥šã«ãªã£ãŠããããšãæ°ã«ãªã£ããããæ¬¡ã«ã¢ããã¿ãŒã«ã©ã®ãããªå€æŽãå
¥ã£ãã®ãã確èªããããšã«ããŸããã Redshiftã¢ããã¿ãŒã®CHANGELOGç¢ºèª CHANGELOGã確èªãããšããã以äžã®éèŠãªç¹ã倿ããŸããã Redshiftã¯ã©ã¹ã¿ãŒãžã®æ¥ç¶ãã©ã€ãã psycopg2 ãã redshift_connector ã«å€æŽãããŠããããš ããã«ããã®æç¹ã§ãéçºç°å¢ã§ã¯dbt runã®ãšã©ãŒãçºçããŠããªãããšããéèŠãªäºå®ã«æ°ã¥ããŸããã é¡äŒŒã®äºè±¡æ¢çŽ¢ã»èª¿æ» dbtãredshift_connectorãenvironmentãããŒã¯ãŒããšããŠã以äžã®æ
å ±æºã§é¡äŒŒäºè±¡ã調æ»ããŸããã dbt-labs/dbt-core ã®Issue dbt-labs/dbt-redshift ã®Issue aws/amazon-redshift-python-driver ã®Issue dbtå
¬åŒã®ãŠãŒã¶ãŒã³ãã¥ãã㣠å®å
šã«äžèŽããäºè±¡ã¯èŠã€ãããŸããã§ãããããããã¯ãŒã¯ã¹ã¿ãã¯ã«é¢é£ãããšæãããIssueãããã€ãçºèŠããŸããã https://github.com/dbt-labs/dbt-redshift/issues/701 https://github.com/dbt-labs/dbt-redshift/issues/518 https://github.com/aws/amazon-redshift-python-driver/issues/212 ãããã®IssueãããGithub ActionsãCodeBuildãªã©ã®ç°å¢ã§åæ§ã®ãšã©ãŒãå ±åãããŠããããšãåãããŸããã ãããã®ã±ãŒã¹ãæç¢ºãªå¯ŸåŠçããããã¯æäŸãããããRedshift Pythonãã©ã€ããŒã«ã¯å®å®ãããããã¯ãŒã¯æ¥ç¶ãå¿
èŠããå®è¡ç°å¢ã«èµ·å ããåé¡ããšããçµè«ã§ã¯ããŒãºãããŠããŸããã ä»åŸã®é²ãæ¹ã決ãã å®è¡ç°å¢ã®å€æŽã§è§£æ±ºã§ããå¯èœæ§ãèŠããŠãããããæ¬¡ã®2ã€ã®å¯Ÿå¿ãé²ããããšã«ããŸããã ã¢ããã¿ãŒã®ããŒãžã§ã³ãææ°ïŒ1.5.12ïŒã«ã¢ããããŒããã ã»ã«ããã¹ãããã©ã³ããŒã§CIã¯ãŒã¯ãããŒã®æ€èšŒãè¡ã æ€èšŒçµæã§ãšã©ãŒãçºçããªããã°CIã¯ãŒã¯ãããŒã®å®è¡ç°å¢ã倿Žãããšã©ãŒãç¶ãå Žåã¯å¥ã®æ¹éãæ€èšãã ãããé©çšã ãã§ã¯è§£æ±ºã§ããªãå¯èœæ§ãé«ããšäºæ³ãããŸããããå¯èœãªå¯Ÿå¿ã¯å
šãŠè©ŠããŠã¿ãããšã«ããŸããã Github Actions ã»ã«ããã¹ãããã©ã³ããŒã§CIã¯ãŒã¯ãããŒæ€èšŒ EC2ã€ã³ã¹ã¿ã³ã¹ïŒAmazon Linux 2023ãt3.smallïŒã«ã»ã«ããã¹ãããã©ã³ããŒãæ§ç¯ããŠCIã¯ãŒã¯ãããŒãå®è¡ãããšããããšã©ãŒã¯çºçããŸããã§ããã ããã«ãããå®è¡ç°å¢ã®å€æŽã解決çãšããŠé²ããããšã決å®ããŸããã Github Actions ã»ã«ããã¹ãããã©ã³ããŒç°å¢ã®éžå® ã»ã«ããã¹ãããã©ã³ããŒã¯èªå·±ç®¡çãå¿
èŠãªãããå®éçšéå§åã«éçšæ¹éãšã»ãã¥ãªãã£é¢ã«ã€ããŠååãªæ€èšãå¿
èŠã§ãã ãã·ã³ã®éçš VMã®ã¡ã³ããã³ã¹ éçãªVMäžå°ã®ç®¡çè² æ
ãçºç ã©ã³ããŒã®ããŒãžã§ã³ç®¡çãã»ãã¥ãªãã£ãããé©çšãOSã¢ããã°ã¬ãŒããªã©ãå¿
èŠ ã¹ã±ãŒãªã³ã°ã®èª²é¡ ãªãŒãã¹ã±ãŒãªã³ã°ã®å®è£
ã¯é床ãªå·¥æ°ãšãªãããçŸå®çã§ã¯ãªã é皌åæéã®æ±ã ã¯ãŒã¯ãããŒã®å®è¡æéã¯1æ¥ã®ããäžéšã®ã¿ ã¯ãŒã¯ãããŒã®prehookãposthookã§ãã·ã³ã®èµ·åã»åæ¢ãå¶åŸ¡ããããšã¯æè¡çã«ã¯å¯èœ ã¯ãŒã¯ãããŒä»¥å€ã®ã¿ã¹ã¯ãçµã¿èŸŒããšã¡ã³ããã³ã¹ã³ã¹ããå¢å€§ããããé¿ããã å®è¡ç°å¢ã®æ§æç®¡ç ã©ã³ããŒã®ãã¹ããã·ã³ã®ã©ã³ã¿ã€ã ãã©ã€ãã©ãªã®æ§æç®¡çãå¿
èŠ ã³ã³ããã«ããç°å¢åé¢ã¯å¯èœã ãã管çè² æ
ãå¢å ãã¯ãŒã¯ãããŒã®å€æŽãå¿
èŠãšãªã ã¢ãã¿ãªã³ã° ãªãœãŒã¹ã»ãã°ã»ã³ã¹ãã®ç£èŠãå¿
èŠ ã»ãã¥ãªãã£é¢ ãã·ã³ã®ã©ã€ããµã€ã¯ã«ç®¡ç ãã¹ããã·ã³ãšã©ã³ããŒã¯ããã¹ãããã©ã³ããŒåæ§ã®ã¯ãªãŒã³ãªç°å¢ãç¶æããããšãæãŸããïŒç°å¢æ±æãããã¯ãã¢ãé²ãããïŒ å¿
èŠæã®ã¿èµ·åããçšæžã¿åŸã¯éããã«çµäºããéçšãæãŸãã å®è¡æš©é管ç ã¯ãŒã¯ãããŒå®è¡æã®ãŠãŒã¶ãŒæš©éãé©åã«å¶åŸ¡ããå¿
èŠããã ã»ããã¢ããã®å©äŸ¿æ§ã®ããã«ãrunner ALL=NOPASSWDããªã©ã®å®æãªèšå®ãè¡ããšãç°å¢ãè匱ã«ãªããªã¹ã¯ããã èŠä»¶ãæŽçããŠã¿ããšèæ
®ãã¹ãç¹ãå€å²ã«ããããããã«æ€èšæŒããããããã§ãã ãã·ã³ã®é©åãªéçšã«ã¯çžåœãªåŽåãå¿
èŠãšãªããããã§ããã°é¿ããããšããã§ãã ãããã®èª²é¡ãæ€èšããªããGithub Actionsã®å
¬åŒããã¥ã¡ã³ãã確èªããŠãããšãããã»ãšãã©ã®èª²é¡ã解決ã§ããããªARCãçºèŠãããããæ€èšŒãçµãŠå®éçšãžã®å°å
¥ã決å®ããŸããã ãŸãšã ä»åã®dbt Coreã¢ããã°ã¬ãŒãäœæ¥ããåŸãããæèšã以äžã«ãŸãšããŸããã ãã®å
容ã誰ãã®åèã«ãªãã°å¹žãã§ãã ã¢ããã°ã¬ãŒãäœæ¥ã«ãããåºæ¬ ã¢ããã°ã¬ãŒãäœæ¥ã®éã¯ã倿Žç¹ã®ç¢ºèªãšåœ±é¿ç¯å²ã®ç¹å®ãæšæºããã»ã¹ãšããŠçµã¿èŸŒãããš ãŸããç°å¢ããšã®ã¢ããã°ã¬ãŒãã¬ã€ãã©ã€ã³ãäºåã«æŽåããããšã§ãæ
åœè
ã«ãããå®å®çãªã¢ããã°ã¬ãŒããå®çŸã§ããå¯èœæ§ãé«ãŸã åé¡è§£æ±ºã¢ãããŒãã®æ¹åç¹ è©°ãŸã£ãŠããæã»ã©å®¢èгçãªèŠç¹ã§ã®ç¶æ³ææ¡ãéèŠããã®ããã«ã¯æèçã«ããªã»ãããã§ãããšè¯ã é©åãªå€æãå°ãããã« å
¬åŒããã¥ã¡ã³ããäžæ¬¡æ
å ±ãåªå
çãªæ
å ±æºãšããŠåç
§ããã㚠解決çã®éžæã«é¢ããèå¯ ãã®å Žã«ãããæé©è§£ã¯ããããæ£è§£ã¯ãªã æé©è§£ã远æ±ããå§¿å¢ã¯å€§åã ããé床ã«åºå·ãããšåãªãæéã®ç¡é§ã«ãªã£ãŠããŸãããšãããããããã©ã³ã¹ãä¿ã€ããšãéèŠ åäžã®è§£æ±ºçã«ãšãããããè€æ°ã®éžæè¢ãæ€èšããããšãéèŠ åèè³æ https://docs.getdbt.com/docs/dbt-versions/core https://docs.getdbt.com/blog/upgrade-dbt-without-fear https://docs.getdbt.com/docs/dbt-versions/core ïž
ããã«ã¡ã¯ïŒNIFTY engineeringããã°éçšããŒã ã§ãïŒ ä»å¹Žããã£ãšããéã«æ®ãããããšãªããŸãããã¯ãªã¹ãã¹ãè¿«ããã¢ããã³ãã«ã¬ã³ããŒã®å£ç¯ãå°æ¥ããŸãããïŒ ãããã£ã°ã«ãŒãã§ã¯æ¯å¹Žãã¢ããã³ãã«ã¬ã³ããŒã«ç©æ¥µçã«åå ããŠãããä»å¹Žã§ãªããš9åç®ã®éå¬ãšãªããŸãïŒ æ¥é ã®ç¥èŠãã¢ãŠããããããæ©äŒãšããŠããããã£ã°ã«ãŒãã®ãšã³ãžãã¢ã楜ãã¿ãªããæé·ããŠããããšãã§ããŠããŸãã ä»å¹Žãçæ§ã«æ°ããªæè¡ãç¥èããå±ãã§ããããšã楜ãã¿ã«ããŠããŸãïŒ ã¢ããã³ãã«ã¬ã³ããŒãšã¯ïŒ å
ã
ã¯ã¯ãªã¹ãã¹ãŸã§ã®æ¥æ°ãã«ãŠã³ãããŠã³ããããã«äœ¿ãããŠããã«ã¬ã³ããŒã§ã12æ1æ¥ããã¯ããŸãã25åãããçªããæ¯æ¥1ã€ãã€éããŠäžã«å
¥ã£ãŠããå°ããªãèåããã¬ãŒã³ããæ¥œãããã®ã§ãã ãã®ã«ã¬ã³ããŒã«ãªãããå®ããããããŒãã«åŸãåå è
ãæã¡åãã§èªèº«ã®ããã°ããµã€ãã«èšäºãæçš¿ããããªã¬ãŒåœ¢åŒã®ããã°å·çã€ãã³ãã§ãïŒ ãããã£ã°ã«ãŒã ã¢ããã³ãã«ã¬ã³ã㌠ãããã£ã°ã«ãŒãã§ã¯ããªãŒããŒããšãªã£ãŠãããŸãã®ã§ã奜ãã«å·çããŠããã£ãŠããŸãã ãŸããèšäºã«é¢ããŠã¯Qiitaæ§ã®ã¢ããã³ãã«ã¬ã³ããŒããŒãžã«ãŠç»é²ãããŠããã ãã å
¬éèªäœã¯NIFTY engineeringã ãããã£ã©ã€ãã¹ã¿ã€ã« Tech Blog ãQiitaã«ããŠããäºå®ã§ãïŒïŒãããã£ããããã£ã©ã€ãã¹ã¿ã€ã«ãã»ã·ãŒã«ã§ããããæçš¿å Žæãç°ãªããŸãïŒ ãããã£ã°ã«ãŒã AdventCalendar 2024 ã¢ããã³ãã«ã¬ã³ããŒã§ã¯ããããã£ã°ã«ãŒãã®ãšã³ãžãã¢ãæ¥é ã®æ¥åã§å¹ã£ãããŠããŠãå
±æããŠãããŸãã®ã§ãã²ãã§ãã¯ããŠã¿ãŠãã ããïŒ