├── devops
├── appdev
│ └── nodejs
│ │ ├── public
│ │ ├── hula_octocat.gif
│ │ └── index.html
│ │ ├── Dockerfile
│ │ ├── function.js
│ │ ├── server.js
│ │ ├── package.json
│ │ ├── __tests__
│ │ └── filterByTerm.spec.js
│ │ └── .gitignore
└── infra
│ ├── aws
│ └── main.tf
│ └── azure
│ └── main.tf
├── .github
├── CODEOWNERS
├── workflows
│ ├── hello-github-actions.yml
│ ├── action-send-slack-msg.yml
│ ├── action-send-team-msg.yml
│ ├── action-terraform-aws.yml
│ ├── action-terraform-azure.yml
│ ├── action-discover-projectboards.yml
│ ├── action-update-issue.yml
│ ├── action-infra-create-azure-webapp.yml
│ ├── action-issueops-demo.yml
│ ├── action-nodejs-cicd.yml
│ └── action-clone-and-create-new-project.yml
└── ISSUE_TEMPLATE
│ └── demo-issueops-template.yml
└── README.md
/devops/appdev/nodejs/public/hula_octocat.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/githubuniverseworkshops/GitHub-Actions-Planet-2021-Korea/HEAD/devops/appdev/nodejs/public/hula_octocat.gif
--------------------------------------------------------------------------------
/devops/appdev/nodejs/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ghcr.io/githubuniverseworkshops/node:latest
2 |
3 | WORKDIR /app
4 |
5 | COPY ["package.json","package-lock.json*","./"]
6 |
7 | RUN npm install
8 |
9 | COPY . .
10 |
11 | CMD ["npm","start"]
12 |
--------------------------------------------------------------------------------
/devops/appdev/nodejs/function.js:
--------------------------------------------------------------------------------
1 | function filterByTerm(inputArr, searchTerm) {
2 | return inputArr.filter(function(arrayElement){
3 | return arrayElement.url.match(searchTerm);
4 | });
5 | }
6 |
7 | module.exports = filterByTerm;
8 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # This is a comment.
2 | # Each line is a file pattern followed by one or more owners.
3 |
4 | # These owners will be the default owners for everything in
5 | # the repo. Unless a later match takes precedence,
6 | # @global-owner1 and @global-owner2 will be requested for
7 | # review when someone opens a pull request.
8 | * @bryantson
9 |
--------------------------------------------------------------------------------
/devops/appdev/nodejs/server.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const app = express();
3 |
4 | app.use(express.static("public"));
5 |
6 | app.get("/", (req, res) => {
7 | res.send("Hello, World");
8 | });
9 |
10 | const server = require("http").createServer({},app);
11 |
12 | server.listen(80, function() {
13 | console.log("HTTPS listening on port 80");
14 | });
15 |
--------------------------------------------------------------------------------
/devops/appdev/nodejs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nodejs-app",
3 | "scripts": {
4 | "test": "jest --coverage --json --outputFile=./output.txt",
5 | "start": "node server.js"
6 | },
7 | "dependencies": {
8 | "jest": "~27.0.5",
9 | "express": "~4.17.1"
10 | },
11 | "jest": {
12 | "collectCoverage": true,
13 | "coverageReporters": ["html"]
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.github/workflows/hello-github-actions.yml:
--------------------------------------------------------------------------------
1 | name: 안녕, 깃허브 액션
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | myName:
7 | description: "이름을 입력해 주세요"
8 | required: true
9 | default: ''
10 |
11 | jobs:
12 | Hello-GitHub-Actions:
13 | runs-on: ubuntu-latest
14 | name: 그냥 "안녕" 인사하고 싶었어요 ^^
15 |
16 | steps:
17 | - name: 안녕하세요, 깃허브 액션
18 | run: |
19 | echo "따뜻한 환영 고마워요! 저의 이름은 ${{ github.event.inputs.myName }} 입니다"
20 | echo "신비로운 깃허브 액션에서 즐거운 시간을 보낼께요!"
21 |
--------------------------------------------------------------------------------
/.github/workflows/action-send-slack-msg.yml:
--------------------------------------------------------------------------------
1 | name: 슬랙 메시지 보내기
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | greeting:
7 | description: "깃허브 액션에서 전송할 인사말을 적어 주세요!"
8 | required: true
9 | default: ''
10 |
11 | jobs:
12 | Hello-GitHub-Actions:
13 | runs-on: ubuntu-latest
14 | name: 슬랙 채널에 전송
15 |
16 | steps:
17 | - name: 깃허브 액션 - 안녕 인사
18 | id: slack
19 | uses: slackapi/slack-github-action@v1.14.0
20 | with:
21 | channel-id: 'github-universe'
22 | slack-message: '깃허브 액션 행성에서 인사합니다! 반가워요. ${{ github.event.inputs.greeting }}'
23 | env:
24 | SLACK_BOT_TOKEN: ${{ secrets.SLACK_TOKEN }}
25 |
--------------------------------------------------------------------------------
/devops/appdev/nodejs/__tests__/filterByTerm.spec.js:
--------------------------------------------------------------------------------
1 | const filterByTerm = require("../function.js");
2 |
3 | describe("Filter function", () => {
4 | test("Test 1", () => {
5 | const input = [
6 | {id: "1", url: "http://www.google.com" },
7 | {id: "2", url: "http://www.msn.com" },
8 | {id: "3", url: "http://www.test.com"}
9 | ];
10 |
11 | const output = [ { id: "3", url: "http://www.test.com" }];
12 |
13 | expect(filterByTerm(input, "test")).toEqual(output);
14 | });
15 |
16 | test("Test 2", () => {
17 | const input = [
18 | {id: "1", url: "http://www.google.com" },
19 | {id: "2", url: "http://www.msn.com" },
20 | {id: "3", url: "http://www.test.com"}
21 | ];
22 |
23 | const output = [ { id: "2", url: "http://www.msn.com" }];
24 |
25 | expect(filterByTerm(input, "msn")).toEqual(output);
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/.github/workflows/action-send-team-msg.yml:
--------------------------------------------------------------------------------
1 | name: 마소 팀즈 메시지 보내기
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | messageTeam:
7 | description: "깃허브 액션 행성에서 전송할 메시지를 적어주세요!"
8 | required: true
9 | default: ''
10 | jobs:
11 |
12 | Send-Message:
13 | runs-on: ubuntu-latest
14 | name: 팀스 메시지 전공
15 |
16 | steps:
17 | - name: 마이크로소프트 팀스로 메시지 보내기
18 | uses: aliencube/microsoft-teams-actions@v0.8.0
19 | with:
20 | webhook_uri: ${{ secrets.MICROSOFT_TEAM_URL }}
21 | title: Hello, GitHub Actions planet
22 | summary: 팀스 메시지 전송 데모 입니다
23 | text: 깃허브 액션 행성으로 오신걸 환영합니다. 불가능이란 없고 다양한 배움과 네트워크를 통해 성장 할수 있는 곳. 그리고 졸귀 문어 고양이도 찾을 수 있습니다.
24 | theme_color: red
25 | sections: '[{ "activityTitle": "${{ github.event.inputs.messageTeam }}" }]'
26 | actions: '[{ "@type": "OpenUri", "name": "깃허브 유니버스", "targets": [{ "os": "default", "uri": "https://githubuniverse.com" }] }]'
27 |
--------------------------------------------------------------------------------
/.github/workflows/action-terraform-aws.yml:
--------------------------------------------------------------------------------
1 | name: AWS 테라폼으로 배포
2 |
3 |
4 | on:
5 | workflow_dispatch:
6 | inputs:
7 | provision_aws:
8 | description: "AWS 인프라 리소스를 만드시겠습니까? (네/아니요)"
9 | required: true
10 | default: '네'
11 |
12 | defaults:
13 | run:
14 | working-directory: devops/infra/aws
15 |
16 | env:
17 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
18 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
19 |
20 | jobs:
21 | Terraform-Script:
22 | runs-on: ubuntu-latest
23 | name: 테라폼 실행
24 | if: ${{ github.event.inputs.provision_aws == '네' }}
25 |
26 | steps:
27 | - name: 파일 체크아웃
28 | uses: actions/checkout@v2
29 |
30 | - name: 테라폼 셋업
31 | uses: hashicorp/setup-terraform@v1
32 |
33 | - name: 테라폼 설정
34 | id: init
35 | run: terraform init
36 |
37 | - name: 테라폼 확인
38 | id: validate
39 | run: terraform validate -no-color
40 |
41 | - name: 테라폼 계획
42 | id: plan
43 | run: terraform plan -no-color
44 | continue-on-error: false
45 |
46 | - name: 테라폼 적용
47 | id: apply
48 | run: terraform apply -auto-approve
49 |
--------------------------------------------------------------------------------
/.github/workflows/action-terraform-azure.yml:
--------------------------------------------------------------------------------
1 | name: Azure 테라폼으로 배포
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | provision_azure:
7 | description: "Azure 인프라 리소스를 만드시겠습니까? (네/아니요)"
8 | required: true
9 | default: '네'
10 |
11 | defaults:
12 | run:
13 | working-directory: devops/infra/azure
14 |
15 | env:
16 | ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
17 | ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
18 | ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
19 | ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
20 |
21 | jobs:
22 | Terraform-Script:
23 | runs-on: ubuntu-latest
24 | name: 테라폼 실행
25 | if: ${{ github.event.inputs.provision_azure == '네' }}
26 |
27 | steps:
28 | - name: 파일 체크아웃
29 | uses: actions/checkout@v2
30 |
31 | - name: 테라폼 셋업
32 | uses: hashicorp/setup-terraform@v1
33 |
34 | - name: 테라폼 설정
35 | id: init
36 | run: terraform init
37 |
38 | - name: 테라폼 확인
39 | id: validate
40 | run: terraform validate -no-color
41 |
42 | - name: 테라폼 계획
43 | id: plan
44 | run: terraform plan -no-color
45 | continue-on-error: false
46 |
47 | - name: 테라폼 적용
48 | id: apply
49 | run: terraform apply -auto-approve
50 |
--------------------------------------------------------------------------------
/.github/workflows/action-discover-projectboards.yml:
--------------------------------------------------------------------------------
1 | name: 만들어진 프로젝트 보드 발견
2 | on:
3 | workflow_dispatch:
4 | inputs:
5 | ownerProject:
6 | description: "현재 만들어진 프로젝트들을 찾아볼까요?"
7 | default: "네"
8 | required: true
9 |
10 |
11 | permissions:
12 | actions: none
13 | checks: none
14 | contents: none
15 | deployments: none
16 | issues: none
17 | packages: none
18 | pull-requests: none
19 | repository-projects: read
20 | security-events: none
21 | statuses: none
22 |
23 | jobs:
24 | discover-different-projects:
25 | name: 프로젝트 보드 찾기
26 | runs-on: ubuntu-latest
27 | steps:
28 | - name: 프로젝트 보드 찾기
29 | uses: actions/github-script@v4.1
30 | with:
31 | github-token: ${{ secrets.GITHUB_TOKEN }}
32 | previews: 'inertia' # 깃허브 프로젝트 API 를 위해선 필수
33 | script: |
34 | try {
35 | listProjects = await github.projects.listForRepo({
36 | owner: context.payload.organization.login ,
37 | repo: context.payload.repository.name ,
38 | per_page: 100
39 | })
40 |
41 | } catch(err) {
42 | throw err
43 | }
44 |
45 | var count = 0
46 | console.log("| 프로젝트 개수 | 프로젝트 이름 | 고유 프로젝트 아이디 | 만든이 |")
47 | listProjects.data.forEach(function(project) {
48 | console.log("| 프로젝트 " + count + " | " + project.name + " | " + project.id + " | " + project.creator.login + " |")
49 | ++ count
50 | })
51 |
52 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 안녕하세요 여러분, 전 문어 고양이 "모나" 에요! :octocat: 🐙 🐱
2 | ## "깃허브 액션 행성에 오신걸 환영 합니다" 👋
3 |
4 | 
5 |
6 | 저흰 **깃허브 액션 행성** 을 항해하며 총 7 개의 대륙에서 결코 쉽진 않지만 흥미로운 깃허브 액션 미션들을 하나 하나 발견하게 될것입니다. 우리가 같이 풀어 나가야 할 깃허브 액션 미션들은 깃허브 이슈에 설명 되어 있습니다.
7 |
8 | ## 난이도 있는 미션들을 달성하며 🏃 문제들을 풀어 나가겠지만 ⛰️ 🔥 재미 있을거에요! 🎮
9 |
10 | 
11 |
12 | ## 🍿 저희의 운항 노선 입니다
13 | 1. [**깃허브 액션 대륙** - 안녕, 깃허브 액션 행성](https://github.com/githubuniverseworkshops/GitHub-Actions-Planet-2021-Korea/issues/1)
14 | 2. [**프로젝트 메니지먼트 대륙** - 제일 중요한건 계획이죠! 깃허브 프로젝트 보드를 통해 이 행성에서 살아남기 위한 계획을 같이 세워요](https://github.com/githubuniverseworkshops/GitHub-Actions-Planet-2021-Korea/issues/2)
15 | 3. [**그룹 액션 대륙** - 각자 필요한 프로젝트 보드를 만들어 보자구!](https://github.com/githubuniverseworkshops/GitHub-Actions-Planet-2021-Korea/issues/3)
16 | 4. [**이슈옵스 대륙** - 이슈옵스를 통해서 모범 기준을 준수하는 레포를 만들어 봐요](https://github.com/githubuniverseworkshops/GitHub-Actions-Planet-2021-Korea/issues/4)
17 | 5. [**메시지 전송 대륙** - 대륙횡단 하기 전에 우리 행성 지구에게 메시지를 전송해요](https://github.com/githubuniverseworkshops/GitHub-Actions-Planet-2021-Korea/issues/5)
18 | 6. [**인프라 데브옵스 대륙** - 테라폼을 사용해서 Azure 클라우드에 인프라 리소스를 생산 해봐요](https://github.com/githubuniverseworkshops/GitHub-Actions-Planet-2021-Korea/issues/6)
19 | 7. [**앱데브 데브옵스 대륙** - CI/CD 프로세스를 통해서 NodeJs 앱을 Azure 클라우드에 배포 해봐요](https://github.com/githubuniverseworkshops/GitHub-Actions-Planet-2021-Korea/issues/7)
20 | 8. [**마무리 데륙** - 여기서 굿바이지만 끝은 아니죠...](https://github.com/githubuniverseworkshops/GitHub-Actions-Planet-2021-Korea/issues/8)
21 |
--------------------------------------------------------------------------------
/.github/workflows/action-update-issue.yml:
--------------------------------------------------------------------------------
1 | name: 이슈 업데이트
2 |
3 | on:
4 | issues:
5 | types: closed
6 |
7 | jobs:
8 | Manage-Issues:
9 | runs-on: ubuntu-latest
10 | name: 이슈 메니지먼트
11 |
12 | steps:
13 | - name: 클로즈 이슈
14 | uses: actions/github-script@v5
15 | with:
16 | script: |
17 | // 이슈 닫기
18 | github.rest.issues.update({
19 | owner: context.payload.organization.login,
20 | repo: context.payload.repository.name,
21 | issue_number: context.issue.number,
22 | state: "closed"
23 | })
24 |
25 |
26 | - name: 오픈 이슈
27 | uses: actions/github-script@v5
28 | with:
29 | script: |
30 | // 다음 이슈 오픈
31 | github.rest.issues.update({
32 | owner: context.payload.organization.login,
33 | repo: context.payload.repository.name,
34 | issue_number: context.issue.number + 1,
35 | state: "open"
36 | })
37 |
38 | - name: 이슈 커멘트
39 | uses: actions/github-script@v5
40 | with:
41 | script: |
42 | // 이슈 커멘트
43 | github.rest.issues.createComment({
44 | owner: context.payload.organization.login,
45 | repo: context.payload.repository.name,
46 | issue_number: context.issue.number,
47 | body: "# 축하합니다. " + context.payload.issue.title + " 에서의 미션을 완성하셨습니다\n " + "\n ## [다음 대륙으로 이동할까요?](https://github.com/" + context.payload.organization.login + "/" + context.payload.repository.name + "/issues/" + (context.payload.issue.number + 1) + ")"
48 | })
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/demo-issueops-template.yml:
--------------------------------------------------------------------------------
1 | name: 이슈옵스를 통한 레포 만들기
2 | description: 이슈옵스는 사용자로 부터 입력 값을 받은 후 레포를 샘플 템플릿 레포를 통해 만들고 다양한 세팅을 설정 합니다
3 | title: "[이슈옵스]: "
4 | labels: ["issueops", "triage"]
5 | assignees:
6 | - bryantson
7 | body:
8 | - type: markdown
9 | attributes:
10 | value: |
11 | 이 레포트를 완성해주시면 감사하겠습니다
12 | - type: input
13 | id: new-repository
14 | attributes:
15 | label: 새로운 레포 이름
16 | description: 새로운 레포의 영문 이름으로 적어 주세요
17 | placeholder: 예. new-repository
18 | validations:
19 | required: true
20 | - type: dropdown
21 | id: template-repository
22 | attributes:
23 | label: 템플릿 레포
24 | description: 사용하고 싶은 템플릿 레포를 골라주세요
25 | options:
26 | - sample-template-repository-universe
27 | validations:
28 | required: true
29 | - type: input
30 | id: team
31 | attributes:
32 | label: 팀 권한
33 | description: 관리자 권한을 적용한 팀 이름을 적어주세요
34 | placeholder: 예. Avengers
35 | validations:
36 | required: false
37 |
38 | - type: checkboxes
39 | id: enable-issues
40 | attributes:
41 | label: Issue 사용하기
42 | description: Issue 를 사용 가능하게 만들까요?
43 | options:
44 | - label: 네, issue 를 사용 가능하길 원합니다
45 | required: false
46 |
47 | - type: checkboxes
48 | id: enable-project
49 | attributes:
50 | label: Project 보드 사용하기
51 | description: Project 보드를 사용 가능하게 만들까요?
52 | options:
53 | - label: 네, project Board 를 사용 가능하길 원합니다
54 | required: false
55 |
56 | - type: checkboxes
57 | id: enable-squash-merge
58 | attributes:
59 | label: Squash Merge 를 사용하기
60 | description: squash merge 를 사용 가능하게 만들까요?
61 | options:
62 | - label: 네, squash merge 를 사용 가능하길 원합니다
63 | required: false
64 |
65 | - type: checkboxes
66 | id: enable-forking
67 | attributes:
68 | label: Fork 를 사용하기
69 | description: Fork 를 사용 가능하게 만들까요?
70 | options:
71 | - label: 네, Fork 를 사용 가능하길 원합니다
72 | required: false
73 |
74 |
--------------------------------------------------------------------------------
/devops/appdev/nodejs/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 안녕, 깃허브 액션
4 |
5 |
6 |
7 |
8 |
9 |
18 |
19 |
깃허브 액션 행성에 오신걸 환영합니다! - 문어 고양이 "모나"
20 |
21 |
깃허브 액션을 통해서 NodeJS 앱을 배포 하는 일에 성공하였습니다!
22 |
23 |

24 |
25 | 다양한 깃허브 페키지 들입니다
26 |
27 |
28 |
29 |
30 | | # |
31 | 페키지 종류 |
32 | 웹 주소 |
33 | 문서 |
34 |
35 |
36 |
37 | | 1 |
38 | 컨테이너 리지스트리 |
39 | ghrc.io |
40 | 컨테이너 리지스트리 문서 |
41 |
42 |
43 | | 2 |
44 | NPM 리지스트리 |
45 | https://npm.pkg.github.com |
46 | NPM 리지스트리 문서 |
47 |
48 |
49 | | 3 |
50 | 루비 Gems 리지스트리 |
51 | https://rubygems.pkg.github.com |
52 | 루비 Gems 문서 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/.github/workflows/action-infra-create-azure-webapp.yml:
--------------------------------------------------------------------------------
1 | name: Azure 웹앱 배포
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | provision_azure:
7 | description: "Azure 웹앱을 배포 할까요? (네/아니요)"
8 | required: true
9 | default: '네'
10 |
11 | env:
12 | AZURE_RESOURCE_GROUP: GitHubUniverse2021-AppDevDemo-group
13 | AZURE_APP_PLAN: actions-bryant-deployment
14 | AZURE_LOCATION: '"Central US"'
15 | #################################################
16 | ### 사용자 설정 값들은 아래에서 찾을수 있습니다 ###
17 | #################################################
18 | #################################################
19 | AZURE_WEBAPP_NAME: sample-nodejs-app-bryant
20 | #################################################
21 |
22 | jobs:
23 | setup-up-azure-resources:
24 | name: Azure 웹앱 배포하기
25 | runs-on: ubuntu-latest
26 |
27 | if: ${{ github.event.inputs.provision_azure == '네' }}
28 |
29 | steps:
30 | - name: 레포 체크아웃
31 | uses: actions/checkout@v2
32 |
33 | - name: Azure 로그인
34 | uses: azure/login@v1
35 | with:
36 | creds: ${{ secrets.AZURE_CREDENTIALS }}
37 |
38 | - name: Azure 리소스 그룹 만들기
39 | if: success()
40 | run: |
41 | az group create --location ${{env.AZURE_LOCATION}} --name ${{env.AZURE_RESOURCE_GROUP}} --subscription ${{secrets.ARM_SUBSCRIPTION_ID}}
42 |
43 | - name: Azure 앱 서비스 플랜 만들기
44 | if: success()
45 | run: |
46 | az appservice plan create --resource-group ${{env.AZURE_RESOURCE_GROUP}} --name ${{env.AZURE_APP_PLAN}} --is-linux --sku F1 --subscription ${{secrets.ARM_SUBSCRIPTION_ID }}
47 |
48 | - name: Azure 웹앱 만들기
49 | if: success()
50 | run: |
51 | az webapp create --resource-group ${{ env.AZURE_RESOURCE_GROUP }} --plan ${{ env.AZURE_APP_PLAN }} --name ${{ env.AZURE_WEBAPP_NAME }} --deployment-container-image-name nginx --subscription ${{secrets.ARM_SUBSCRIPTION_ID}}
52 |
53 | - name: 깃허브 페키지를 위한 웹앱 설정
54 | if: success()
55 | run: |
56 | az webapp config container set --docker-custom-image-name nginx --docker-registry-server-password ${{secrets.GITHUB_TOKEN}} --docker-registry-server-url https://ghcr.io --docker-registry-server-user ${{github.actor}} --name ${{ env.AZURE_WEBAPP_NAME }} --resource-group ${{ env.AZURE_RESOURCE_GROUP }} --subscription ${{secrets.ARM_SUBSCRIPTION_ID}}
57 |
--------------------------------------------------------------------------------
/devops/appdev/nodejs/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # Snowpack dependency directory (https://snowpack.dev/)
45 | web_modules/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 | .parcel-cache
78 |
79 | # Next.js build output
80 | .next
81 | out
82 |
83 | # Nuxt.js build / generate output
84 | .nuxt
85 | dist
86 |
87 | # Gatsby files
88 | .cache/
89 | # Comment in the public line in if your project uses Gatsby and not Next.js
90 | # https://nextjs.org/blog/next-9-1#public-directory-support
91 | # public
92 |
93 | # vuepress build output
94 | .vuepress/dist
95 |
96 | # Serverless directories
97 | .serverless/
98 |
99 | # FuseBox cache
100 | .fusebox/
101 |
102 | # DynamoDB Local files
103 | .dynamodb/
104 |
105 | # TernJS port file
106 | .tern-port
107 |
108 | # Stores VSCode versions used for testing VSCode extensions
109 | .vscode-test
110 |
111 | # yarn v2
112 | .yarn/cache
113 | .yarn/unplugged
114 | .yarn/build-state.yml
115 | .yarn/install-state.gz
116 | .pnp.*
117 |
--------------------------------------------------------------------------------
/devops/infra/aws/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_launch_configuration" "example" {
2 | image_id = "ami-0c55b159cbfafe1f0"
3 | instance_type = "t2.micro"
4 | security_groups = [aws_security_group.instance.id]
5 |
6 | user_data = <<-EOF
7 | #!/bin/bash
8 | echo "Hello, World" > index.html
9 | nohup busybox httpd -f -p ${var.server_port} &
10 | EOF
11 |
12 | lifecycle {
13 | create_before_destroy = true
14 | }
15 | }
16 |
17 | resource "aws_autoscaling_group" "example" {
18 | launch_configuration = aws_launch_configuration.example.name
19 | vpc_zone_identifier = data.aws_subnet_ids.default.ids
20 |
21 | target_group_arns = [aws_lb_target_group.asg.arn]
22 | health_check_type = "ELB"
23 |
24 | min_size = 2
25 | max_size = 10
26 |
27 | tag {
28 | key = "Name"
29 | value = "terraform-cicd-demo"
30 | propagate_at_launch = true
31 | }
32 | }
33 |
34 | data "aws_vpc" "default" {
35 | default = true
36 | }
37 |
38 | data "aws_subnet_ids" "default" {
39 | vpc_id = data.aws_vpc.default.id
40 | }
41 |
42 | provider "aws" {
43 | region= "us-east-2"
44 | }
45 |
46 | variable "server_port" {
47 | description = "The port the server will be used for HTTP requests"
48 | type = number
49 | default = 8080
50 | }
51 |
52 | output "alb_dns_name" {
53 | value = aws_lb.example.dns_name
54 | description = "The domain name of the laod balancer"
55 | }
56 |
57 | resource "aws_security_group" "instance" {
58 | name = "terraform-cicd-demo-instance"
59 |
60 | ingress {
61 | from_port = var.server_port
62 | to_port = var.server_port
63 | protocol = "tcp"
64 | cidr_blocks = ["0.0.0.0/0"]
65 | }
66 | }
67 |
68 | resource "aws_lb" "example" {
69 | name = "terraform-cicd-demo-lb"
70 | load_balancer_type = "application"
71 | subnets = data.aws_subnet_ids.default.ids
72 | security_groups = [aws_security_group.alb.id]
73 | }
74 |
75 | resource "aws_lb_listener" "http" {
76 | load_balancer_arn = aws_lb.example.arn
77 | port = 80
78 | protocol = "HTTP"
79 |
80 | default_action {
81 | type = "fixed-response"
82 |
83 | fixed_response {
84 | content_type = "text/plain"
85 | message_body = "404: page not found"
86 | status_code = 404
87 | }
88 | }
89 | }
90 |
91 | resource "aws_security_group" "alb" {
92 | name = "terraform-cicd-demo-alb"
93 |
94 | # Allow inbound HTTP requests
95 | ingress {
96 | from_port = 80
97 | to_port = 80
98 | protocol = "tcp"
99 | cidr_blocks = ["0.0.0.0/0"]
100 | }
101 |
102 | egress {
103 | from_port = 0
104 | to_port = 0
105 | protocol = "-1"
106 | cidr_blocks = ["0.0.0.0/0"]
107 | }
108 | }
109 |
110 | resource "aws_lb_target_group" "asg" {
111 | name = "terraform-cicd-demo-tg"
112 | port = var.server_port
113 | protocol = "HTTP"
114 | vpc_id = data.aws_vpc.default.id
115 |
116 | health_check {
117 | path = "/"
118 | protocol = "HTTP"
119 | matcher = "200"
120 | interval = 15
121 | timeout = 3
122 | healthy_threshold = 2
123 | unhealthy_threshold = 2
124 | }
125 | }
126 |
127 | resource "aws_lb_listener_rule" "asg" {
128 | listener_arn = aws_lb_listener.http.arn
129 | priority = 100
130 |
131 | condition {
132 | path_pattern {
133 | values = ["*"]
134 | }
135 | }
136 |
137 | action {
138 | type = "forward"
139 | target_group_arn = aws_lb_target_group.asg.arn
140 | }
141 | }
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/.github/workflows/action-issueops-demo.yml:
--------------------------------------------------------------------------------
1 | name: 이슈옵스를 통해서 레포 만들기
2 | on:
3 | issues:
4 | types: [opened]
5 |
6 | jobs:
7 | Create-Repo:
8 | name: 레포 만들기
9 | runs-on: ubuntu-latest
10 | if: contains(github.event.issue.labels.*.name, 'issueops')
11 | steps:
12 |
13 | - name: 깃허브 레포를 만듭니다
14 | uses: actions/github-script@v5
15 | with:
16 | github-token: ${{ secrets.CUSTOM_TOKEN }}
17 | script: |
18 |
19 | bodySplit = context.payload.issue.body.split("\n")
20 |
21 | let newRepo = bodySplit[2]
22 | let templateRepo = bodySplit[6]
23 | let teams = bodySplit[10].split(",")
24 | let enableIssue = bodySplit[14].includes("X")
25 | let enableProject = bodySplit[18].includes("X")
26 | let enableSquashMerge = bodySplit[22].includes("X")
27 | let enableForking = bodySplit[26].includes("X")
28 |
29 | try {
30 | await github.rest.repos.createUsingTemplate({
31 | template_owner: context.payload.organization.login,
32 | template_repo: templateRepo,
33 | name: newRepo,
34 | owner: context.payload.organization.login,
35 | description: "깃허브 액션을 통해 만든 새로운 레포 ",
36 | include_all_branches: true,
37 | private: false
38 | })
39 | } catch(err) {
40 | throw err
41 | }
42 |
43 | try {
44 | await github.rest.repos.update({
45 | owner: context.payload.organization.login,
46 | private: true,
47 | repo: newRepo,
48 | has_issues: enableIssue,
49 | has_projects: enableProject,
50 | allow_squash_merge: enableSquashMerge
51 | })
52 | } catch(err) {
53 | throw err
54 | }
55 |
56 | try {
57 | await github.rest.repos.updateBranchProtection({
58 | "owner": context.payload.organization.login,
59 | "repo": newRepo,
60 | "branch": 'main',
61 | "required_status_checks": { "strict": true, "contexts": [] },
62 | "enforce_admins": true,
63 | "required_pull_request_reviews": {"dismissal_restrictions": {"users":[], "teams":[]}, "dismiss_stale_reviews": false, "require_code_owner_reviews": true, "required_approving_review_count": 1},
64 | "restrictions" : { "users": [], "teams": [], "apps": [] }
65 | })
66 | } catch(err) {
67 | throw err
68 | }
69 |
70 | try {
71 | await github.rest.teams.addOrUpdateRepoPermissionsInOrg({
72 | org: context.payload.organization.login,
73 | owner: context.payload.organization.login,
74 | repo: newRepo,
75 | team_slug: teams,
76 | permission: 'admin'
77 | })
78 | } catch(err) {
79 | throw err
80 | }
81 |
82 | try {
83 | await github.rest.issues.createComment({
84 | issue_number: context.issue.number,
85 | owner: context.repo.owner,
86 | repo: context.repo.repo,
87 | body: '새로운 레포는 다음 주소에서 : https://github.com/' + context.payload.organization.login + "/" + newRepo
88 | })
89 | } catch(err) {
90 | throw err
91 | }
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/.github/workflows/action-nodejs-cicd.yml:
--------------------------------------------------------------------------------
1 | name: NodeJS CI/CD 프로세스
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | test-nodejs:
7 | description: "NodeJS CI/CD 프로세스를 실행할까요? (네/아니요)"
8 | required: true
9 | default: '네'
10 | env:
11 | DOCKER_IMAGE_NAME: my-custom-nodeapp
12 | DOCKER_IMAGE_VERSION: ${{ github.sha }}
13 | AZURE_WEBAPP_NAME: sample-nodejs-app-bryant
14 | IMAGE_REGISTRY_URL: ghcr.io
15 | AZURE_RESOURCE_GROUP: GitHubUniverse2021-AppDevDemo-group
16 |
17 | defaults:
18 | run:
19 | working-directory: devops/appdev/nodejs
20 |
21 | jobs:
22 | NodeJS-Test:
23 | runs-on: ubuntu-latest
24 | name: NodeJS 빌드
25 | if: ${{ github.event.inputs.test-nodejs == '네' }}
26 |
27 | steps:
28 | - name: 파일 체크아웃
29 | uses: actions/checkout@v2
30 |
31 | - name: NodeJS 셋업
32 | uses: actions/setup-node@v2
33 | with:
34 | node-version: ${{ matrix.node-version }}
35 |
36 | - name: NPM 모듈 설치
37 | run: npm install
38 |
39 | - name: NPM 테스트 돌리기
40 | run: npm test
41 |
42 | - name: 테스트 결과를 깃허브 아티팩트로 올리기
43 | uses: actions/upload-artifact@main
44 | with:
45 | name: 테스트 결과
46 | path: ${{ github.workspace }}/devops/appdev/nodejs/output.txt
47 |
48 | - name: 깃허브 아티팩트에 테스트 카버리지 올리기
49 | uses: actions/upload-artifact@main
50 | with:
51 | name: 테스트 카버리지 결과
52 | path: ${{ github.workspace }}/devops/appdev/nodejs/coverage
53 |
54 | Build-Image:
55 | needs: NodeJS-Test
56 | runs-on: ubuntu-latest
57 | name: 컨테이너 이미지 빌드
58 |
59 | steps:
60 | - name: 파일 체크 아웃
61 | uses: actions/checkout@v2
62 |
63 | - name: 깃허브 컨테이너 리지스트리 로그인
64 | uses: docker/login-action@v1
65 | with:
66 | registry: ghcr.io
67 | username: ${{ github.repository_owner }}
68 | password: ${{ secrets.TOKEN_PACKAGE }}
69 |
70 | - name: 빌드 그리고 푸쉬
71 | id: docker_build
72 | uses: docker/build-push-action@v2
73 | with:
74 | context: devops/appdev/nodejs
75 | push: true
76 | tags: ghcr.io/githubuniverseworkshops/nodejs/${{ env.DOCKER_IMAGE_NAME }}:${{ env.DOCKER_IMAGE_VERSION }}
77 |
78 | Deploy-Azure:
79 | runs-on: ubuntu-latest
80 | needs: Build-Image
81 | name: 컨테이너를 Azure 웹앱에 배포
82 | steps:
83 | - name: Azure CLI 로 로그인
84 | uses: azure/login@v1
85 | with:
86 | creds: ${{ secrets.AZURE_CREDENTIALS }}
87 |
88 | - name: GHCR 리지스트리 로그인
89 | uses: azure/docker-login@v1
90 | with:
91 | login-server: ghcr.io
92 | username: ${{ github.actor }}
93 | password: ${{ secrets.TOKEN_PACKAGE }}
94 |
95 | - name: 웹앱 ACR 인증
96 | uses: Azure/appservice-settings@v1
97 | with:
98 | app-name: ${{ env.AZURE_WEBAPP_NAME }}
99 | app-settings-json: |
100 | [
101 | {
102 | "name": "DOCKER_REGISTRY_SERVER_PASSWORD",
103 | "value": "${{ secrets.TOKEN_PACKAGE }}",
104 | "slotSetting": false
105 | },
106 | {
107 | "name": "DOCKER_REGISTRY_SERVER_URL",
108 | "value": "https://ghcr.io",
109 | "slotSetting": false
110 | },
111 | {
112 | "name": "DOCKER_REGISTRY_SERVER_USERNAME",
113 | "value": "${{ github.actor }}",
114 | "slotSetting": false
115 | }
116 | ]
117 |
118 | - name: Azure 웹앱 컨테이너로 배포
119 | uses: azure/webapps-deploy@v2
120 | with:
121 | app-name: ${{ env.AZURE_WEBAPP_NAME }}
122 | images: ${{ env.IMAGE_REGISTRY_URL }}/githubuniverseworkshops/nodejs/${{ env.DOCKER_IMAGE_NAME }}:${{ env.DOCKER_IMAGE_VERSION }}
123 |
124 |
125 |
--------------------------------------------------------------------------------
/devops/infra/azure/main.tf:
--------------------------------------------------------------------------------
1 | # Configure the Microsoft Azure Provider
2 | terraform {
3 | required_providers {
4 | azurerm = {
5 | source = "hashicorp/azurerm"
6 | version = "~>2.0"
7 | }
8 | }
9 | }
10 | provider "azurerm" {
11 | features {}
12 | }
13 |
14 | # Create a resource group if it doesn't exist
15 | resource "azurerm_resource_group" "myterraformgroup" {
16 | name = "GitHubUniverseRG"
17 | location = "eastus"
18 |
19 | tags = {
20 | environment = "Terraform Demo"
21 | }
22 | }
23 |
24 | # Create virtual network
25 | resource "azurerm_virtual_network" "myterraformnetwork" {
26 | name = "myVnet"
27 | address_space = ["10.0.0.0/16"]
28 | location = "eastus"
29 | resource_group_name = azurerm_resource_group.myterraformgroup.name
30 |
31 | tags = {
32 | environment = "Terraform Demo"
33 | }
34 | }
35 |
36 | # Create subnet
37 | resource "azurerm_subnet" "myterraformsubnet" {
38 | name = "mySubnet"
39 | resource_group_name = azurerm_resource_group.myterraformgroup.name
40 | virtual_network_name = azurerm_virtual_network.myterraformnetwork.name
41 | address_prefixes = ["10.0.1.0/24"]
42 | }
43 |
44 | # Create public IPs
45 | resource "azurerm_public_ip" "myterraformpublicip" {
46 | name = "myPublicIP"
47 | location = "eastus"
48 | resource_group_name = azurerm_resource_group.myterraformgroup.name
49 | allocation_method = "Dynamic"
50 |
51 | tags = {
52 | environment = "Terraform Demo"
53 | }
54 | }
55 |
56 | # Create Network Security Group and rule
57 | resource "azurerm_network_security_group" "myterraformnsg" {
58 | name = "myNetworkSecurityGroup"
59 | location = "eastus"
60 | resource_group_name = azurerm_resource_group.myterraformgroup.name
61 |
62 | security_rule {
63 | name = "SSH"
64 | priority = 1001
65 | direction = "Inbound"
66 | access = "Allow"
67 | protocol = "Tcp"
68 | source_port_range = "*"
69 | destination_port_range = "22"
70 | source_address_prefix = "*"
71 | destination_address_prefix = "*"
72 | }
73 |
74 | tags = {
75 | environment = "Terraform Demo"
76 | }
77 | }
78 |
79 | # Create network interface
80 | resource "azurerm_network_interface" "myterraformnic" {
81 | name = "myNIC"
82 | location = "eastus"
83 | resource_group_name = azurerm_resource_group.myterraformgroup.name
84 |
85 | ip_configuration {
86 | name = "myNicConfiguration"
87 | subnet_id = azurerm_subnet.myterraformsubnet.id
88 | private_ip_address_allocation = "Dynamic"
89 | public_ip_address_id = azurerm_public_ip.myterraformpublicip.id
90 | }
91 |
92 | tags = {
93 | environment = "Terraform Demo"
94 | }
95 | }
96 |
97 | # Connect the security group to the network interface
98 | resource "azurerm_network_interface_security_group_association" "example" {
99 | network_interface_id = azurerm_network_interface.myterraformnic.id
100 | network_security_group_id = azurerm_network_security_group.myterraformnsg.id
101 | }
102 |
103 | # Generate random text for a unique storage account name
104 | resource "random_id" "randomId" {
105 | keepers = {
106 | # Generate a new ID only when a new resource group is defined
107 | resource_group = azurerm_resource_group.myterraformgroup.name
108 | }
109 |
110 | byte_length = 8
111 | }
112 |
113 | # Create storage account for boot diagnostics
114 | resource "azurerm_storage_account" "mystorageaccount" {
115 | name = "diag${random_id.randomId.hex}"
116 | resource_group_name = azurerm_resource_group.myterraformgroup.name
117 | location = "eastus"
118 | account_tier = "Standard"
119 | account_replication_type = "LRS"
120 |
121 | tags = {
122 | environment = "Terraform Demo"
123 | }
124 | }
125 |
126 | # Create (and display) an SSH key
127 | resource "tls_private_key" "example_ssh" {
128 | algorithm = "RSA"
129 | rsa_bits = 4096
130 | }
131 | output "tls_private_key" {
132 | value = tls_private_key.example_ssh.private_key_pem
133 | sensitive = true
134 | }
135 |
136 | # Create virtual machine
137 | resource "azurerm_linux_virtual_machine" "myterraformvm" {
138 | name = "myVM"
139 | location = "eastus"
140 | resource_group_name = azurerm_resource_group.myterraformgroup.name
141 | network_interface_ids = [azurerm_network_interface.myterraformnic.id]
142 | size = "Standard_DS1_v2"
143 |
144 | os_disk {
145 | name = "myOsDisk"
146 | caching = "ReadWrite"
147 | storage_account_type = "Premium_LRS"
148 | }
149 |
150 | source_image_reference {
151 | publisher = "Canonical"
152 | offer = "UbuntuServer"
153 | sku = "18.04-LTS"
154 | version = "latest"
155 | }
156 |
157 | computer_name = "myvm"
158 | admin_username = "azureuser"
159 | disable_password_authentication = true
160 |
161 | admin_ssh_key {
162 | username = "azureuser"
163 | public_key = tls_private_key.example_ssh.public_key_openssh
164 | }
165 |
166 | boot_diagnostics {
167 | storage_account_uri = azurerm_storage_account.mystorageaccount.primary_blob_endpoint
168 | }
169 |
170 | tags = {
171 | environment = "Terraform Demo"
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/.github/workflows/action-clone-and-create-new-project.yml:
--------------------------------------------------------------------------------
1 | name: 프로젝트 보드 카피
2 | on:
3 | workflow_dispatch:
4 | inputs:
5 | projectID:
6 | description: "카피하실 프로젝트 보드 아이디를 적어 주세요"
7 | default: "13877300"
8 | required: true
9 | descNewProject:
10 | description: "깃허브 아이드를 적어 주세요"
11 | default: "@깃허브아이디"
12 | required: true
13 |
14 | permissions:
15 | actions: none
16 | checks: none
17 | contents: none
18 | deployments: none
19 | issues: none
20 | packages: none
21 | pull-requests: none
22 | repository-projects: write
23 | security-events: none
24 | statuses: none
25 |
26 | env:
27 | PROJECT_ID: ${{ github.event.inputs.projectID }}
28 |
29 | jobs:
30 | newProject:
31 | name: 깃허브 프로젝트 카피
32 | runs-on: ubuntu-latest
33 | steps:
34 | - name: 깃허브 프로젝트 카피
35 | uses: actions/github-script@v4.1
36 | with:
37 | github-token: ${{ secrets.GITHUB_TOKEN }}
38 | previews: 'inertia' # 깃허브 프로젝트 API 를 위해 필수
39 | script: |
40 | console.log("======= 고유 프로젝트 아이디 " + ${{ env.PROJECT_ID }} + " 에서 데이터를 추출 합니다 ==============")
41 |
42 | // 기존 프로젝트 보드 column 읽기:
43 | try {
44 | listColumns = await github.projects.listColumns({
45 | project_id: ${{ env.PROJECT_ID }}
46 | })
47 | } catch(err) {
48 | throw err
49 | }
50 |
51 | console.log("총 " + listColumns.length + " column 을 다음 고유 프로젝트 아이디 에서 찾았습: " + ${{ env.PROJECT_ID }})
52 |
53 | // column 아이디를 저장하는 리스트:
54 | listColumnIDs = []
55 | // column 이름을 저장하는 리스트:
56 | listColumnNames = []
57 |
58 | // column 을 룹하면서 데이터 추출:
59 | listColumns.data.forEach(function(column) {
60 | listColumnIDs.push(column.id)
61 | listColumnNames.push(column.name)
62 | })
63 |
64 | // 포맷 안된 카드를 저장하는 리스트:
65 | listAllCardsUnformatted = []
66 |
67 | // 카드 데이터:
68 | try {
69 | for(var i=0; i < listColumnIDs.length; ++ i) {
70 | listCards4Column = await github.projects.listCards({
71 | column_id: listColumnIDs[i]
72 | })
73 | listAllCardsUnformatted.push(listCards4Column.data)
74 | }
75 |
76 | } catch(err) {
77 | throw err
78 | }
79 |
80 | // 카드를 저장하는 리스트:
81 | listAllCards = []
82 |
83 | // 새로운 리스트 :
84 | listAllCardsUnformatted.forEach(function(cardsPerColumn) {
85 | listCardsPerColumn = []
86 |
87 | // ITERATING through all cards in this column:
88 | cardsPerColumn.forEach(function(card) {
89 | listCardsPerColumn.push(card.note ? card.note : card.content_id)
90 | })
91 |
92 | // STORING the reversed card orders since it is ordered in an opposite way:
93 | listAllCards.push(listCardsPerColumn.reverse())
94 | })
95 |
96 | console.log("프로젝트 보드 안에 있는 카드들 => " + JSON.stringify(listAllCards))
97 |
98 | // column 개수를 나타냅니다:
99 | nListColumns = listAllCards.length;
100 |
101 | console.log("\n========= 프로젝트 만들기 ==================\n")
102 |
103 | // 새로운 프로젝트 보드를 나타냅니다:
104 | var projectObj="";
105 |
106 | // 인풋 값으로 새로운 프로젝트 보드를 만듭니다:
107 | try {
108 | projectObj = await github.projects.createForRepo({
109 | owner: context.payload.organization.login,
110 | repo: context.payload.repository.name,
111 | name: "${{ github.event.inputs.descNewProject }} 깃허브 액션 행성 생존계획"
112 | })
113 | } catch(err) {
114 | throw err
115 | }
116 |
117 | console.log("다음 Project ID 를 가진 새로운 프로젝트 보드가 만들어졌습니다: " + projectObj.data.id)
118 | console.log("다음, column 하고 카드를 만듭니다")
119 |
120 | // 새로운 프로젝트 보드의 카드를 만듭니다:
121 | for(var iColumn=0; iColumn < nListColumns; ++ iColumn) {
122 | try {
123 | // CREATE a new column attached to our new project ID:
124 | var columnObj = await github.projects.createColumn({
125 | name: listColumnNames[iColumn],
126 | project_id: projectObj.data.id
127 | })
128 |
129 | // 총 카드 수를 계산 합니다:
130 | nCardsPerColumn = listAllCards[iColumn].length
131 |
132 | // 한 column 안에 있는 카드들을 저장합니다:
133 | listOrderedCardsPerColumn = listAllCards[iColumn]
134 |
135 | console.log("이 column 의 : " + JSON.stringify(listOrderedCardsPerColumn))
136 |
137 | // 카드를 만듭니다:
138 | for(var iCard = 0; iCard < nCardsPerColumn; ++ iCard) {
139 | try {
140 | var cardObj = await github.projects.createCard({
141 | column_id: columnObj.data.id,
142 | note: listOrderedCardsPerColumn[iCard]
143 | })
144 |
145 | } catch(err) {
146 | console.log("카드 만드는 중 에러: " + err);
147 | throw err;
148 | }
149 | }
150 | } catch(err) {
151 | console.log("일반 에러: " + err);
152 | throw err
153 | }
154 | }
155 |
156 | console.log("끝!")
157 |
158 |
--------------------------------------------------------------------------------