GitHub Release artifacts in Buddy: auto-deploy new releases

Buddy now supports GitHub Release artifacts. Connect a repository, and Buddy creates artifact versions from the files attached to new releases. A new version can trigger a pipeline that, for example, deploys a GitHub pre-release to staging and requires approval before deploying a stable release to production. In our demo, one release candidate passed its GitHub Actions tests but failed the Buddy smoke test before deployment.

What does a GitHub Release artifact give you?

If you already publish application packages in GitHub releases, the release process does not need to change. A Buddy pipeline can download, test, and deploy the attached files.

Each artifact version is named after the release tag and contains the assets attached to that release. Buddy does not download the source code archives that GitHub generates automatically. A pipeline triggered by a new version receives its name and whether it is a pre-release, so it can download the right package and pick the target environment.

Image loading...Four versions of the status-api artifact, two marked as Pre-release

Info
A GitHub Release artifact is synchronized in one direction: GitHub -> Buddy. Its versions are read-only in Buddy, and adding a version or a file fails with Artifact version is read only. To create releases from Buddy, use the GitHub Release action.

Example: RC to staging, stable to production

We tested this scenario on a small Node app, status-api, with a /health endpoint. GitHub Actions publishes the app as an archive attached to the release. Buddy downloads it, checks that the app starts after installing production dependencies, and routes the run based on the release type:

  • Pre-release: deploy to staging and check the deployed version.
  • Stable: manual approval, deploy to production, and check the deployed version.
  • Failed smoke test: stop the run before deployment.

Image loading...Deploy release pipeline: Artifact version Create trigger and eight actions, five with conditions

In the demo, both environments are Buddy sandboxes. You can replace them with your own deployment targets. The stable release is packaged separately and goes through its own smoke test. This example routes different releases to staging and production. Promoting the same package from staging to production requires a different pipeline setup.

How do you create a GitHub Release artifact?

Create the artifact in the Artifacts tab of your workspace and choose the GitHub Release type:

  • Repository - a repo from your GitHub integration.
  • Scope - where the artifact is available: workspace, project, or environment.
  • Include draft releases - whether to create versions from drafts.
  • Include pre-releases - whether to create versions from pre-releases.
  • Retention artifact version pattern - retention rules for versions matching a name pattern, e.g. v*-rc.*.

When you connect a repository, Buddy does not import its existing releases. Versions are created only from new ones, so connecting a repo with a release history will not trigger any pipelines.

Image loading...GitHub Release artifact settings: workspace scope, GitHub integration, status-api repository, pre-releases included

The pipeline requires the Use role in the artifact's Permissions tab. If a run stops with Pipeline not allowed to Use artifact, verify that the pipeline has this permission.

How do you run a pipeline on a new release?

Add the Artifact version: Create trigger and select the artifact. In our example, it is status-api. In YAML:

yaml
events:
- type: CREATE_ARTIFACT_VERSION
  artifacts:
  - identifier: status-api
    scope: WORKSPACE

A run triggered by a new GitHub Release artifact version gets two variables, and the whole pipeline is built on them:

Variable Value
BUDDY_RUN_ARTIFACT_VERSION release tag, e.g. v1.1.0-rc.2
BUDDY_RUN_ARTIFACT_VERSION_PRERELEASE true for a GitHub pre-release, false for stable

Buddy reads the release type from the pre-release flag on GitHub, not from the tag name. If your workflow does not set the flag, an RC reaches the pipeline as stable.

The full YAML is at the end of the post.

Downloading the version

Download artifact version downloads the version that triggered the run ($BUDDY_RUN_ARTIFACT_VERSION) into its own directory. The pipeline filesystem persists between runs, so a directory per version keeps the archives of different releases apart.

yaml
- action: Download release
  type: DOWNLOAD_ARTIFACT_VERSION
  artifact: status-api
  version: $BUDDY_RUN_ARTIFACT_VERSION
  destination_path: release/$BUDDY_RUN_ARTIFACT_VERSION
  overwrite: true

What did we check in the demo?

Each of the four releases triggered a separate run. Only v1.1.0-rc.1 stopped before deployment:

Image loading...Deploy release runs #1-#4, each started by a status-api artifact version

Smoke test before deployment

The smoke test unpacks the archive, installs dependencies with --omit=dev, starts the server, and polls /health every second. If the server does not respond within 10 seconds, the action prints its log and fails the run. The tested app directory, including node_modules, is then transferred to the sandbox for deployment.

Release v1.1.0-rc.1 failed this test. The app imported dotenv, but the package was in devDependencies. Tests in GitHub Actions passed after npm ci, but running the package after npm ci --omit=dev ended with an error:

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'dotenv' imported from /buddy/status-api/app/src/server.js

Image loading...Run for v1.1.0-rc.1 stopped on the smoke test, staging and production actions skipped

After we moved the package to dependencies, release v1.1.0-rc.2 passed the test and reached staging:

json
{"status":"ok","version":"1.1.0-rc.2","env":"staging"}

Staging or production

Action conditions check BUDDY_RUN_ARTIFACT_VERSION_PRERELEASE. For a GitHub pre-release, the variable is true, for a stable release it is false. An action whose condition is not met shows up in the run as Skipped. This is the condition on the staging deploy action:

yaml
trigger_conditions:
- trigger_condition: VAR_IS
  trigger_variable_key: BUDDY_RUN_ARTIFACT_VERSION_PRERELEASE
  trigger_variable_value: "true"

Image loading...Deploy to staging condition: BUDDY_RUN_ARTIFACT_VERSION_PRERELEASE is true

Deploying to a sandbox is a regular Transfer action with the sandbox as the target, followed by a Manage Sandbox action with the APP_RESTART operation. The sandbox runs the app with npm start in /home/buddy/status-api, has an HTTP endpoint on port 3000 and an APP_ENV variable. See Sandboxes in pipelines for setup details.

Image loading...Transfer action with the status-staging sandbox as target, /app from the pipeline filesystem uploaded to /home/buddy/status-api

The stable v1.1.0 passed the smoke test, skipped staging, and waited the Approve Run action (WAIT_FOR_APPLY). The run waits until someone with permissions approves it. Details in Manual approval.

Image loading...Run for v1.1.0 waiting on the Approve production deploy action

Checking the version

The last action calls the public endpoint of the sandbox the app was deployed to, extracts the version field with node -p, and compares it with the release tag without the v. The app needs a moment to restart, so the action tries up to 10 times, every 3 seconds, before it marks the deploy as failed.

How do you prepare the release on GitHub?

GitHub Actions publishes a release for every v* tag. The workflow runs the tests, writes the version from the tag into package.json, packs the app into a single archive, and publishes the release. Tags with a hyphen, such as v1.1.0-rc.1, are marked as pre-releases. The workflow needs the contents: write permission, otherwise gh release create is denied access. The step that publishes the release:

yaml
- name: Publish release
  env:
    GH_TOKEN: ${{ github.token }}
  run: |
    TAG="${GITHUB_REF_NAME}"
    FLAGS=""
    case "$TAG" in *-*) FLAGS="--prerelease" ;; esac
    gh release create "$TAG" "status-api-${TAG}.tar.gz" --title "$TAG" --generate-notes $FLAGS

Full pipeline

The YAML below recreates the demo pipeline. Replace the artifact identifier, target names, archive name, and endpoint URLs with your own.

yaml
- pipeline: deploy-release
  name: Deploy release
  events:
  - type: CREATE_ARTIFACT_VERSION
    artifacts:
    - identifier: status-api
      scope: WORKSPACE
  actions:
  - action: Download release
    type: DOWNLOAD_ARTIFACT_VERSION
    artifact: status-api
    version: $BUDDY_RUN_ARTIFACT_VERSION
    destination_path: release/$BUDDY_RUN_ARTIFACT_VERSION
    overwrite: true
  - action: Smoke test production install
    type: BUILD
    docker_image_name: library/node
    docker_image_tag: "24"
    shell: BASH
    commands: |-
      rm -rf app && mkdir app
      tar -xzf "release/$BUDDY_RUN_ARTIFACT_VERSION/status-api-$BUDDY_RUN_ARTIFACT_VERSION.tar.gz" -C app
      cd app
      npm ci --omit=dev
      PORT=3000 node src/server.js > /tmp/server.log 2>&1 &
      for i in $(seq 1 10); do
        curl -fsS localhost:3000/health && exit 0
        sleep 1
      done
      cat /tmp/server.log
      exit 1
  - action: Deploy to staging
    type: TRANSFER
    trigger_conditions:
    - trigger_condition: VAR_IS
      trigger_variable_key: BUDDY_RUN_ARTIFACT_VERSION_PRERELEASE
      trigger_variable_value: "true"
    input_type: BUILD_ARTIFACTS
    local_path: /app
    remote_path: /home/buddy/status-api
    targets:
    - status-staging
  - action: Restart staging app
    type: SANDBOX_MANAGE
    trigger_conditions:
    - trigger_condition: VAR_IS
      trigger_variable_key: BUDDY_RUN_ARTIFACT_VERSION_PRERELEASE
      trigger_variable_value: "true"
    operation: APP_RESTART
    targets:
    - status-staging
  - action: Approve production deploy
    type: WAIT_FOR_APPLY
    trigger_conditions:
    - trigger_condition: VAR_IS
      trigger_variable_key: BUDDY_RUN_ARTIFACT_VERSION_PRERELEASE
      trigger_variable_value: "false"
    comment: Deploy $BUDDY_RUN_ARTIFACT_VERSION to production?
  - action: Deploy to production
    type: TRANSFER
    trigger_conditions:
    - trigger_condition: VAR_IS
      trigger_variable_key: BUDDY_RUN_ARTIFACT_VERSION_PRERELEASE
      trigger_variable_value: "false"
    input_type: BUILD_ARTIFACTS
    local_path: /app
    remote_path: /home/buddy/status-api
    targets:
    - status-production
  - action: Restart production app
    type: SANDBOX_MANAGE
    trigger_conditions:
    - trigger_condition: VAR_IS
      trigger_variable_key: BUDDY_RUN_ARTIFACT_VERSION_PRERELEASE
      trigger_variable_value: "false"
    operation: APP_RESTART
    targets:
    - status-production
  - action: Check live version
    type: BUILD
    docker_image_name: library/node
    docker_image_tag: "24"
    shell: BASH
    commands: |-
      if [ "$BUDDY_RUN_ARTIFACT_VERSION_PRERELEASE" = "true" ]; then
        URL="https://<your-staging-endpoint>/health"
      else
        URL="https://<your-production-endpoint>/health"
      fi
      EXPECTED="${BUDDY_RUN_ARTIFACT_VERSION#v}"
      for i in $(seq 1 10); do
        LIVE=$(curl -fsS "$URL" | node -p 'JSON.parse(require("fs").readFileSync(0, "utf8")).version' 2>/dev/null || true)
        echo "live: ${LIVE:-no response}, expected: $EXPECTED"
        [ "$LIVE" = "$EXPECTED" ] && exit 0
        sleep 3
      done
      exit 1

To deploy GitHub releases automatically, start small: connect a GitHub Release artifact to a repo that already publishes releases and add a pipeline with just the download and the smoke test. Add the staging and production deploys once the smoke test has passed on a few releases.

Jarek Dylewski

Jarek Dylewski

Customer Support

A journalist and an SEO specialist trying to find himself in the unforgiving world of coders. Gamer, a non-fiction literature fan and obsessive carnivore. Jarek uses his talents to convert the programming lingo into a cohesive and approachable narration.

Nov 13, 2026
Share