Database Release CI/CD with GitHub Actions

Estimated: 40 mins

This tutorial shows you how to build an automated database release pipeline using GitHub Actions and Bytebase API. You'll learn to:

  1. Create a streamlined database release workflow where you can:

    • Submit SQL migrations through GitHub
    • Automatically run SQL reviews on pull requests
    • Auto-create and deploy Bytebase releases when merging to main
  2. Manually control rollouts by stage (available with Pro/Enterprise plans)

While we use GitHub Actions in this guide, you can apply these concepts to other CI platforms like GitLab CI, Bitbucket Pipelines, or Azure DevOps using the Bytebase API.

Prerequisites

Automatic Rollout across environments

Step 1 - Start Bytebase with ngrok

For production tunneling, consider Cloudflare Zero Trust.

ngrok is a reverse proxy tunnel, and in our case, we need it for a public network address in order to receive webhooks from VCS. ngrok we used here is for demonstration purposes.

ngrok-reverse-proxy

  1. Run Bytebase in Docker with the following command:

    docker run --rm --init \
      --name bytebase \
      --publish 8080:8080 --pull always \
      --volume ~/.bytebase/data:/var/opt/bytebase \
      bytebase/bytebase:3.5.0
  2. Bytebase is running successfully in Docker, and you can visit it via localhost:8080. Register an admin account and it will be granted the workspace admin role automatically.

  3. Login to ngrok Dashboard and complete the Getting Started steps to install and configure. If you want to use the same domain each time you launch ngrok, go to Cloud Edge > Domains, where you'll find the domain <<YOURS>>.ngrok-free.app linked to your account.

  4. Run the ngrok command ngrok http --domain=<<YOURS>>.ngrok-free.app 8080 to start ngrok with your specific domain, and you will see the output displayed below:

    terminal-ngrok

  5. Log in Bytebase and click the gear icon (Settings) on the top right. Click General under Workspace. Paste <<YOURS>>.ngrok-free.app as External URL under Network section and click Update.

    external-url

  6. Now you can access Bytebase via <<YOURS>>.ngrok-free.app.

Step 2 - Create Service Account

  1. Log in as Workspace Admin, and go to IAM & Admin > Users & Groups. Click + Add User, fill in with api-sample, choose the Workspace DBA role sufficient for this tutorial and click Confirm. service-account-create

  2. Find the newly created service account and Copy Service Key. We will use this token to authenticate the API calls. service-account-key

If you have Enterprise Plan, you can create a Custom Role for the service account which require fewer permissions, and assign this role instead of DBA:

  • plans.create
  • plans.get
  • plans.preview
  • releases.check
  • releases.create
  • releases.get
  • rollouts.create
  • rollouts.get
  • rollouts.list
  • sheets.create
  • sheets.get
  • taskRuns.create
  • planCheckRuns.list
  • planCheckRuns.run

Step 3 - Fork the Example Repository and Configure Variables

  1. Fork bytebase/release-cicd-workflows-example. There are two workflows in this repository:

    • .github/workflows/bytebase-check-release.yml: Lint the SQL migration files after the PR is created.
    • .github/workflows/bytebase-release-cicd.yml: Create a release in Bytebase after the PR is merged to the main branch.
  2. Go into .github/workflows/bytebase-release-cicd.yml and .github/workflows/bytebase-check-release.yml. In the env section, replace the variable values with your own and commit the changes.

    • BYTEBASE_URL: your ngrok url
    • BYTEBASE_PROJECT: projects/project-sample (the sample project in the Bytebase)
    • BYTEBASE_SERVICE_ACCOUNT: api-example@service.bytebase.com (the service account you created in the previous step)
    • BYTEBASE_TARGETS: instances/test-sample-instance/databases/hr_test,instances/prod-sample-instance/databases/hr_prod (the two default databases in the sample project)
  3. You may paste the password of the service account you created in the previous step directly after service-secret or replace service-secret value as ${{secrets.BYTEBASE_PASSWORD}}. Go to Settings > Secrets and Variables > Actions, click New repository secret, and add BYTEBASE_PASSWORD.

  4. Go to Actions tab, enable actions workflow run.

Step 4 - Create the Release and Roll out

To create migration files to trigger release creation, the files have to match the following pattern:

  • A migration file should start with digits, which is also its version. e.g. 20250101001_create_table_ddl.sql.
  • A migration file may end with 'ddl' or 'dml' to indicate its change type. If it doesn't end with any of the two, its change type is DDL by default.
  1. Within your forked repository, create the following migration files under migrations directory:

    • 20250101001_create_table_t1_ddl.sql
    CREATE TABLE t1 (
      id INT
    );
    • 20250101002_drop_t2_create_table_t2_ddl.sql
    DROP TABLE t1;
    CREATE TABLE t2 (
      id INT
    );
  2. Commit to a new branch and create a pull request, the bytebase-check-release workflow will be triggered.

    gh-sql-review-no-pass

    You got this SQL review is because by default, there is a SQL review configured on Prod environment in Bytebase.

    bb-sql-review

  3. According to the SQL review result, you can do some changes to the SQL files and push to the branch. Then you should see the SQL review has passed.

    CREATE TABLE t1(id INT PRIMARY KEY NOT NULL);
    ALTER TABLE t1 RENAME TO "t1_del";
    
    DROP TABLE "t1_del";
    
    CREATE TABLE t2(id INT PRIMARY KEY NOT NULL);

    gh-sql-review-pass

  4. When the SQL review is passed, you can merge the pull request. The bytebase-release-cicd workflow will be triggered to create a release in Bytebase and then roll out automatically. Go to Actions tab, you can see the workflow run and pass.

    gh-cicd-release-pass

  5. If you click the link in the Create release section, you can see the release is created in Bytebase.

    bb-release

  6. If you click the link in the Rollout section, you can see the rollout is applied to the databases.

    bb-rollout

Breakdown of the GitHub Actions Workflow

  1. Check out your repo and log in to Bytebase to gain the access token.

    - name: Checkout
      uses: actions/checkout@v4
    - name: Login to Bytebase
      id: login
      uses: bytebase/login-action@main
      with:
        bytebase-url: ${{ env.BYTEBASE_URL }}
        service-key: ${{ env.BYTEBASE_SERVICE_ACCOUNT }}
        service-secret: ${{ secrets.BYTEBASE_PASSWORD }}
  2. The create_release step scans the files matching the pattern and collects them into a bundle. Note that these files should also obey the naming scheme mentioned above.

    The bundle is first sent for check. Because we set FAIL_ON_ERROR, the release will be created in Bytebase only when the check passes.

    - name: Create release
      id: create_release
      uses: bytebase/create-release-action@v1
      with:
        url: ${{ env.BYTEBASE_URL }}
        token: ${{ steps.login.outputs.token }}
        project: ${{ env.BYTEBASE_PROJECT }}
        file-pattern: ${{ env.FILE_PATTERN }}
        check-release: 'FAIL_ON_ERROR'
        targets: ${{ env.BYTEBASE_TARGETS }}
        validate-only: 'false'
  3. Create a rollout and wait for completion.

    - name: Create plan
      id: create_plan
      uses: bytebase/create-plan-from-release-action@v1
      with:
        url: ${{ env.BYTEBASE_URL }}
        token: ${{ steps.login.outputs.token }}
        project: ${{ env.BYTEBASE_PROJECT }}
        release: ${{ steps.create_release.outputs.release }}
        targets: ${{ env.BYTEBASE_TARGETS }}
        # 'FAIL_ON_ERROR' will fail the action if plan checks report errors.
        # Use 'SKIP' to skip the check.
        # Use 'FAIL_ON_WARNING' to fail if plan checks report warning.
        check-plan: 'FAIL_ON_ERROR'
        validate-only: 'false'
    
    - name: Rollout
      id: rollout
      uses: bytebase/rollout-action@v1
      with:
        url: ${{ env.BYTEBASE_URL }}
        token: ${{ steps.login.outputs.token }}
        plan: ${{ steps.create_plan.outputs.plan }}
        # set target-stage to exit after the stage completes
        # target-stage: 'test'

    These are the steps:

    • Create the plan from the release
    • Check the plan
    • Create the rollout
    • Wait for the rollout to complete

    In the create_plan step, you can set check-plan to FAIL_ON_ERROR to fail the action if plan checks report errors. Use SKIP to skip plan checks. Use FAIL_ON_WARNING to fail the action if plan checks report warning.

    The rollout pipeline stages are created on demand in the Rollout step.

Manual Rollout by Environment (Pro or Enterprise Plan)

In the previous section, once the PR is merged, we create a release and roll out it to both test and prod environments automatically. You can also manually control the rollout by stage if you have Pro or Enterprise plan.

  1. Upgrade your Bytebase plan to Pro or Enterprise plan, assign the license to your instances.

  2. Click Environments on the left sidebar, click Prod tab, set Rollout Policy as Manual rollout by dedicated roles.

  3. Go to the .github/workflows/bytebase-release-cicd.yml file, look at the Rollout section, You can use target-stage to early exit the step. When the target stage completes, it exits. If target-stage is not provided or not found, Rollout will wait until all stages complete. Uncomment the last line target-stage: 'test' and commit the changes.

    - name: Rollout
      id: rollout
      uses: bytebase/rollout-action@v1
      with:
        url: ${{ env.BYTEBASE_URL }}
        token: ${{ steps.login.outputs.token }}
        plan: ${{ steps.create_plan.outputs.plan }}
        # set target-stage to exit after the stage completes
        # target-stage: 'test'
  4. You can find the Environment ID as target-stage in your Environments page.

  5. Create a new branch with this file, and create a pull request. Merge it to the main branch.

    • 20250101003_create_table_t3_ddl.sql
    CREATE TABLE t3(id INT PRIMARY KEY NOT NULL);
  6. Go to the Actions tab, you can see the workflow run and pass. Expand the Rollout section, the rollout is created and the stage is skipped.

    gh-rollout-skip

  7. Click the link in the Rollout section, you will go to the Rollout Pipeline in Bytebase.

    bb-manual-rollout

  8. Click the arrow button, and click Confirm. The Prod Stage will be created.

    bb-confirm-add

  9. Click into the script and click Run. The script will be applied to the prod database.

    bb-prod-run

  10. Go back to the Rollout Pipeline page, you can see the Prod Stage is completed.

    bb-rollout-done

Summary

Now you have learned how to create a release and then rollout to the database in Bytebase with GitHub Action. If you want to trigger a release creation with other git providers (e.g. GitLab, Bitbucket, Azure DevOps), you may customize the workflow file.

Edit this page on GitHub