---
# System prepended metadata

title: Approvals in github

---

# Approvals in github
https://github.com/github/c2c-actions/issues/1389 

## Goals
- Shouldn't consume billing resources
- Incorporate as much as we can inside YML (no diversions to using UI unless required)

## Talking points
- `reviewers` list should be in YML?
    - If not, may be provide a way to store them as secrets?
    - Or special UI trick to store them

## Proposals

### Approvals at step level

```
name: Approval step level example

on: push

integrations:
  # We define these special integrations with set of well defined variables user have to provide
  # Just like `env` these will be injected with secrets context
  slack:
    channel_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}

jobs:
  my-job:
    name: My Job
    runs-on: ubuntu-latest
    steps:
    - name: Say hello
      env:
        NAME: Octocat
      run: |
        echo $NAME
    - name: Wait for approval
      # custom Id
      id: approval
      # type approval make this a special step and won't consume billing resources (runs on server)
      type: approval
      # reviewers is optional as well, effectively making this a step that's "pauses" (think of pausing between rings in azure devops deployment)
      reviewers:
        - github/c2c-actions-service
        - github/c2c-actions
        - yaananth
      # timeout, to be used as pausing or timing out
      timeout: 
        period: 1day
        # default outcome for the step
        outcome: success # or failure or skipped (so this can be used as "pausing")
      # How many approvals is required?
      required: 1
      # How would you want to be notified?
      integration:
        - slack
        # or email as we add more, maps to `integrations` on top of workflow
    - name: Print if approved
      if: ${{ steps.approval.outcome == 'success' }}
      run: |
        echo "Success!"
    - name: Print if skipped
      if: ${{ steps.approval.outcome == 'skipped' }}
      run: |
        echo "Skipped/Just used for pausing!"
    - name: Print if failure
      if: ${{ steps.approval.outcome == 'failure' }}
      run: |
        echo "Rejected!"
```

#### Pros
- No new concepts (other than integrations)
- Familiar step conclusions flow 
- Can also be used to pause workflow (at step level)
- Can also be used at job level, by having a job with single step and using `needs` for other jobs
    - Note: This needs `steps` context to condition based on individual special step result

#### Cons
- `runs-on: ubuntu-latest` for a job might be confusing when it has a step that doesn't consume runner
- Introduces `type` for a step, what more types we plan to add later? 
- Need to expose `steps` context to `needs` context so that user can condition based on each special step result (just like different gates for approvals at job level proposal)
- Might need some changes on runner side, as runner expects to just run steps sequentially on the machine

### Approvals at job level

```
name: Approval job level example

on: push

integrations:
  # We define these special integrations with set of well defined variables user have to provide
  # Just like `env` these will be injected with secrets context
  slack:
    channel_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}

jobs:
  approval-job:
    name: Approval job
    gates:
      approval:
        # reviewers is optional as well, effectively making this a step that's "pauses" (think of pausing between rings in azure devops deployment)
        reviewers:
          - github/c2c-actions-service
          - github/c2c-actions
          - yaananth
        # timeout, to be used as pausing or timing out
        timeout: 
          period: 1day
          # default outcome for the step
          outcome: success # or failure or skipped (so this can be used as "pausing")
        # How many approvals is required?
        required: 1
        # How would you want to be notified?
        integration:
          - slack
          # or email as we add more, maps to `integrations` on top of workflow
  after-approval-job:
    name: My Job
    runs-on: ubuntu-latest
    needs: approval-job
    steps:
      # https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#needs-context
      - name: Print if approved
        if: ${{ needs.approval-job.result == 'success' }}
        run: |
          echo "Success!"
      # No "skipped" result as of now
      # Need to introduce gates context so that we can check multiple gates results as well
      # so `needs.approval-job.result` for the whole job, `needs.approval-job.gates.approval.result` for just `approval` gate
      - name: Print if failure
        if: ${{ needs.approval-job.result == 'failure' }}
        run: |
          echo "Rejected!"
```

#### Pros
- Can add gates to any existing jobs easily
- Easy to read "this job is gated by these"
- Can be reused for multiple jobs, by having a empty job with gates and using `needs` for other jobs
- Adheres to general concepts, job just needs to "wait" before it actually runs

#### Cons
- Need to introduce `gates` context to `jobs`
- Can't be used for "pausing" between deployments unless new `skipped` result is added
- Introduces `gates` for a job, what more gates we plan to add later? 
	
