# 배포 작업

배포 REST API를 사용하여 서버 및 타사 앱과 상호 작용하는 사용자 지정 도구를 빌드할 수 있습니다.

REST API를 사용하여 소유한 서버에 호스트된 GitHub 프로젝트를 배포할 수 있습니다. 배포 및 상태를 관리하는 엔드포인트에 대한 자세한 정보는 [배포에 대한 REST API 엔드포인트](/ko/enterprise-server@3.22/rest/deployments)을(를) 참조하세요. REST API를 사용하면 코드가 기본 분기에 배치되는 순간, 배포를 조정할 수도 있습니다. 자세한 내용은 [CI 서버 빌드](/ko/enterprise-server@3.22/rest/guides/building-a-ci-server)을(를) 참조하세요.

이 가이드에서는 REST API로 사용할 수 있는 설정을 보여 줍니다.
이 시나리오에서는 다음을 수행합니다.

* 끌어오기 요청 병합하기.
* CI가 완료되면 그에 따라 끌어오기 요청의 상태를 설정합니다.
* 끌어오기 요청이 병합되면 서버로의 배포를 실행합니다.

CI 시스템 및 호스트 서버는 상상한 그대로가 됩니다. Heroku, Amazon 또는 완전히 다른 무언가가 될 수 있습니다. 이 가이드의 핵심은 통신을 관리하는 서버를 설정하고 구성하는 것입니다.

아직 다운로드하지 않은 경우 [`ngrok`을 다운로드](https://ngrok.com/)하고 [사용](https://ngrok.com/docs/getting-started/) 방법을 알아보세요. 로컬 애플리케이션을 인터넷에 노출하는 데 매우 유용한 도구라고 합니다.

참고: [플랫폼 샘플 리포지토리에서](https://github.com/github/platform-samples/tree/master/api/ruby/delivering-deployments) 이 프로젝트에 대한 전체 소스 코드를 다운로드할 수 있습니다.

## 서버 작성

로컬 연결이 잘 작동하는지 확인하기 위해 간단한 Sinatra 앱을 작성합니다.
먼저 다음을 살펴보겠습니다.

```ruby
require 'sinatra'
require 'json'

post '/event_handler' do
  payload = JSON.parse(params[:payload])
  "Well, it worked!"
end
```

(Sinatra의 작동 방식에 익숙하지 않은 경우 [ 가이드를 읽는 것이](http://www.sinatrarb.com/) 좋습니다.)

이 서버를 시작합니다. 기본적으로 Sinatra는 포트 `4567`에서 시작되므로 `ngrok`도 수신 대기를 시작하도록 구성할 수 있습니다.

이 서버가 작동하려면 웹후크를 사용하여 리포지토리를 설정해야 합니다. 끌어오기 요청을 만들거나 병합할 때마다 webhook가 실행되도록 구성해야 합니다.

편하게 실험할 수 있는 리포지토리를 만들어 보세요.
[
@octocat의 스푼/나이프 리포지토리](https://github.com/octocat/Spoon-Knife)를 제안해보겠습니다.

그런 다음, 리포지토리에 새 webhook를 만들고, `ngrok`에서 제공한 URL을 피드하고, 콘텐츠 형식으로 `application/x-www-form-urlencoded`를 선택합니다.

**웹후크 업데이트**를 클릭합니다.
`Well, it worked!`라는 응답이 표시되어야 합니다.
좋습니다!
**개별 이벤트 선택**을 클릭하고 다음을 선택합니다.

* 배포
* 배포 상태
* 끌어오기 요청

관련 작업이 발생할 때마다 서버로 전송되는 이벤트 GitHub 입니다. 이제 끌어오기 요청이 병합될 때만 처리하도록 \_\_ 서버를 구성합니다.

```ruby
post '/event_handler' do
  @payload = JSON.parse(params[:payload])

  case request.env['HTTP_X_GITHUB_EVENT']
  when "pull_request"
    if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
      puts "A pull request was merged! A deployment should start now..."
    end
  end
end
```

무슨 일입니까?
GitHub가 전송하는 모든 이벤트에는 `X-GitHub-Event` HTTP 헤더가 첨부됩니다. 지금은 PR 이벤트만 신경을 써야 합니다. 끌어오기 요청이 병합되면(해당 상태는 `closed`이고 `merged`가 `true`임) 배포를 시작합니다.

이 개념 증명을 테스트하려면 테스트 리포지토리에서 브랜치의 몇 가지 변경을 하고, 풀 리퀘스트를 생성한 후 병합하세요. 서버가 그에 따라 응답해야 합니다!

## 배포 작업 처리

서버가 배치되고 코드가 검토되고 끌어오기 요청이 병합되면 프로젝트를 배포하려고 합니다.

먼저 병합 시 끌어오기 요청을 처리하도록 이벤트 수신기를 수정하고 배포에 주의를 기울입니다.

```ruby
when "pull_request"
  if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
    start_deployment(@payload["pull_request"])
  end
when "deployment"
  process_deployment(@payload)
when "deployment_status"
  update_deployment_status
end
```

끌어오기 요청의 정보에 따라 먼저 `start_deployment` 메서드를 작성합니다.

```ruby
def start_deployment(pull_request)
  user = pull_request['user']['login']
  payload = JSON.generate(:environment => 'production', :deploy_user => user)
  @client.create_deployment(pull_request['head']['repo']['full_name'], pull_request['head']['sha'], {:payload => payload, :description => "Deploying my sweet branch"})
end
```

배포에는 일부 메타데이터가 `payload` 및 `description` 형식으로 연결되어 있을 수 있습니다. 이러한 값은 선택 사항이지만 정보를 로깅하고 나타내는 데 사용하는 것이 좋습니다.

새 배포가 만들어지면 완전히 별도의 이벤트가 트리거됩니다. 이때문에 `switch`에 대한 이벤트 처리기에 새 `deployment` 사례가 있는 것입니다. 배포가 트리거될 때 이 정보를 사용하여 알림을 받을 수 있습니다.

배포에 다소 시간이 걸릴 수 있으므로 배포가 만들어진 시기 및 배포 상태와 같은 다양한 이벤트를 수신 대기하려고 합니다.

일부 작업을 수행하는 배포를 시뮬레이트하고 출력에 미치는 영향을 살펴보겠습니다. 먼저 `process_deployment` 메서드를 완료해 보겠습니다.

```ruby
def process_deployment
  payload = JSON.parse(@payload['payload'])
  # you can send this information to your chat room, monitor, pager, etc.
  puts "Processing '#{@payload['description']}' for #{payload['deploy_user']} to #{payload['environment']}"
  sleep 2 # simulate work
  @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'pending')
  sleep 2 # simulate work
  @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'success')
end
```

마지막으로, 상태 정보를 콘솔 출력으로 저장하는 과정을 시뮬레이트합니다.

```ruby
def update_deployment_status
  puts "Deployment status for #{@payload['id']} is #{@payload['state']}"
end
```

어떤 결과가 나타나는지 분석해 보겠습니다.
`start_deployment` 이벤트를 트리거하는 `deployment`에 의해 새 배포가 만들어집니다. 여기에서 `process_deployment`를 호출하여 진행 중인 작업을 시뮬레이트합니다. 또한 이 처리 중에 `create_deployment_status`를 호출하여 `pending`으로 상태를 전환할 때 어떤 결과가 나타나는지를 수신자가 알도록 할 수 있습니다.

배포가 완료되면 상태를 `success`로 설정합니다.

## 결론

GitHub에서는 몇 년 동안 배포를 관리하기 위해 버전을 `Heaven` 사용했습니다. 일반적인 흐름은 기본적으로 위에서 빌드한 서버와 동일합니다.

* CI 검사 상태(성공 또는 실패)에 대한 응답 대기
* 필요한 검사가 성공하면 끌어오기 요청을 병합합니다.
* `Heaven` 는 병합된 코드를 가져와 스테이징 및 프로덕션 서버에 배포합니다.
* 그동안 `Heaven`은 또한 채팅방에 있는 [Hubot](https://github.com/github/hubot)을 통해 모든 사람에게 빌드 소식을 알립니다.

정말 간단하죠. 이 예제를 사용하기 위해 고유한 배포 설정을 빌드할 필요가 없습니다.
항상 [GitHub 통합](https://github.com/integrations) 사용할 수 있습니다.