# Automated deployment using a CI/CD pipeline  You can build a continuous integration and continuous deployment (CI/CD) pipeline to automate deployments to production. You can also use these pipelines to run automated tests before deploying. You can use any CI/CD platform to build a pipeline, such as GitHub Actions, CircleCI, GitLab, or Jenkins. ## Using `ggt` in a CI/CD pipeline  To set up a CI/CD pipeline for your Gadget app, you need to: 1. Use [source control](https://docs.gadget.dev/guides/source-control) to manage your Gadget project(s). 2. Generate a [CLI token](https://docs.gadget.dev/guides/development-tools/cli#how-to-generate-a-cli-token) for your app used to authenticate `ggt`. 3. [Deploy changes to production](https://docs.gadget.dev/guides/environments/deployment) using `ggt deploy`. `ggt deploy` will automatically run `ggt push` under the hood if the local filesystem, which is your test runner and git branch, does not match the hosted environment. This is so the latest code and configuration on your specified git branch will always be deployed to production. ### Using a CLI token to run `ggt deploy`  You need to provide a CLI token so that `ggt` can make authenticated requests to your Gadget app. [Read our docs on generating a token here](https://docs.gadget.dev/guides/development-tools/cli#how-to-generate-a-cli-token). Once the CLI token has been generated, it needs to be stored as a secret in the CI platform you are using. After storing your CLI token as a secret, the token can be safely used in your pipeline to run authenticated `ggt` commands. Here is how you can pass a CLI token to `ggt` in a GitHub Action: ```yml // in using a CLI token to deploy in a CI/CD pipeline - uses: actions/checkout@v4 - name: Install ggt # first, install ggt in the test runner environment run: | npm install -g ggt@latest ggt version shell: bash - name: Deploy to production # deploy to production for the passed in app and environment run: | ggt deploy --app= --env= --force --allow-unknown-directory shell: bash env: GGT_TOKEN: ${{ secrets.GGT_TOKEN }} ``` The `--allow-unknown-directory` flag is required when an app's `.gadget` folder has not been pulled into your test runner before running `ggt deploy`. This flag allow you to deploy to production without a `.gadget/sync.json` file. The `--force` flag is used to overwrite the current hosted environment with whatever currently exists in the git branch, ensuring that the lasted code and configuration is deployed. ### Example: Use a pre-built GitHub Action  Here is an example running `ggt deploy` using the [pre-built `gadget-inc/ggt-deploy-action@v1`](https://github.com/gadget-inc/ggt-deploy-action). `ggt-deploy-action` will automatically install `ggt` and run `ggt deploy` with the passed in options. 1. Generate a [CLI token](https://docs.gadget.dev/guides/development-tools/cli#how-to-generate-a-cli-token) in Gadget. 2. Go to your GitHub repository's **Settings**, then find the **Secrets** section. Add a new secret named `GGT_TOKEN` and paste your CLI token as the value. This step ensures that your token is securely stored and accessible in your GitHub Actions workflow. 3. In your Gadget app, create a `.github/workflows` directory. Inside, you'll create a `YAML` file for your workflow. 4. In your `YAML` workflow file, paste the token as shown below in the config steps of your Github Action. ```yaml // in action.yml name: CI/CD Pipeline on: push: branches: - main # or any other branch you want to deploy from jobs: deploy: steps: - name: Checkout the current repository uses: actions/checkout@v4 - name: Deploy to Gadget Production uses: gadget-inc/ggt-deploy-action@v1 with: app: '' environment: '' # The environment you are deploying to production token: ${{ secrets.GGT_TOKEN }} # Add your CLI token allow-issues: 'false' # Optionally, continue deployment even if there are issues ``` This action will be run automatically every time you push to the `main` branch. It will: * install `ggt` into your test runner environment * take the latest code and configurations from your git branch and push it to the specified Gadget environment * deploy that environment to production ## Automated testing  You can also run automated tests as part of a CI/CD pipeline. This means you run tests between pushing your changes from git to Gadget, and deploying. To run automated tests in a CI/CD pipeline, you need to: 1. Use [source control](https://docs.gadget.dev/guides/source-control) to manage your Gadget project(s). 2. Generate a [CLI token](https://docs.gadget.dev/guides/development-tools/cli#how-to-generate-a-cli-token) for your app used to authenticate `ggt`. 3. Update a Gadget environment with the latest code and configuration from your git branch using `ggt push`: ```bash // in sample ggt push command ggt push --app= --env= --force --allow-unknown-directory ``` 4. Run your tests against the updated environment. A `ggt pull` may be required to bring in files not maintained in source control if you are running tests using a Gadget API client. 5. [Deploy changes to production](https://docs.gadget.dev/guides/environments/deployment) using `ggt deploy`. ### Example CI/CD with tests: GitHub Actions  Here is an example of pushing all code to a staging environment in Gadget, then running a unit test suite in a GitHub Action: ```yml // in a GitHub Action that pushing to a "staging" environment, runs tests, and deploys name: deploy to prod on: push: branches: [main] env: GADGET_ENV: staging GADGET_TEST_API_KEY: ${{ secrets.GADGET_TEST_API_KEY }} jobs: push: # first job, push changes from git to a "staging" environment runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install ggt run: | npm install -g ggt ggt version shell: bash - name: Push code to test/CI environment run: | ggt push --app= --env=staging --force --allow-unknown-directory shell: bash env: GGT_TOKEN: ${{ secrets.GGT_TOKEN }} test: # second job, run automated tests runs-on: ubuntu-latest needs: push steps: - uses: actions/checkout@v4 - name: Create env file # a .env file is required for an API key (stored as a secret) run: | touch .env echo GADGET_TEST_API_KEY="$GADGET_TEST_API_KEY" >> .env echo GADGET_ENV="$GADGET_ENV" >> .env - name: Install ggt # each job is a fresh environment, so ggt must be reinstalled run: | npm install -g ggt ggt version shell: bash - name: Pull client files into env # pull .gadget folder into test runner run: | ggt pull --app= --env=staging --force --allow-unknown-directory shell: bash env: GGT_TOKEN: ${{ secrets.GGT_TOKEN }} - name: Install dependencies run: yarn --frozen-lockfile - name: Run tests run: yarn test deploy: # final job, deploy staging to production runs-on: ubuntu-latest needs: test steps: - uses: actions/checkout@v4 - name: Install ggt run: | npm install -g ggt ggt version shell: bash - name: Deploy to production # run ggt deploy to deploy changes from staging to production run: | ggt deploy --app= --env=staging --force --allow-all shell: bash env: GGT_TOKEN: ${{ secrets.GGT_TOKEN }} ``` In this example, a CLI token (`GGT_TOKEN`) and an API key for the staging environment (`GADGET_TEST_API_KEY`) are stored as secrets in GitHub. This could also be compressed into a single job and `ggt` would only need to be installed once.