Skip to content

replicatedhq/replicated-actions

Repository files navigation

Compatibility Actions

Examples

Development

The development workflow will run the workflow on every push to a branch that is not the main branch. It will create a new release that is promoted to a channel with the same name as the branch. The next job will setup a compatibility matrix of clusters, deploy the app and execute some tests. Once everything is successful the created clusters and customers will be removed again. Based on your preference you can either use the simplified prepare-cluster version, or the highly customizable version.

Prepare Cluster

See the example workflow for more details and also the prepare-cluster directory for the actual action.

name: development
on:
push:
branches:
- '*' # matches every branch that doesn't contain a '/'
- '*/*' # matches every branch containing a single '/'
- '**' # matches every branch
- '!main' # excludes main
jobs:
compatibility-matrix:
strategy:
fail-fast: false
matrix:
cluster: [ {distribution: kind, version: v1.25.3}, {distribution: k3s, version: v1.26}]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Package Helm Chart for Replicated
id: package-helm-chart
run: |
helm package . -u
- name: Prepare Cluster
id: prepare-cluster
uses: replicatedhq/compatibility-actions/prepare-cluster@v1
with:
app-slug: ${{ secrets.REPLICATED_APP }}
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
chart: wordpress-enterprise-0.3.1.tgz
kubernetes-distribution: ${{ matrix.cluster.distribution }}
kubernetes-version: ${{ matrix.cluster.version }}
helm-chart-name: wordpress-enterprise

Customizable

Installation with Helm

See the example workflow for more details.

name: development-helm
on:
push:
branches:
- '*' # matches every branch that doesn't contain a '/'
- '*/*' # matches every branch containing a single '/'
- '**' # matches every branch
- '!main' # excludes main
jobs:
push-to-replicated:
runs-on: ubuntu-22.04
outputs:
channel-slug: ${{ steps.create-release.outputs.channel-slug}}
steps:
- uses: actions/checkout@v3
- name: Define App Version
run: echo "APP_VERSION=0.0.1-${GITHUB_REF_NAME//[^a-zA-Z0-9]/}.${GITHUB_RUN_ID}${GITHUB_RUN_ATTEMPT}" >> $GITHUB_ENV
- name: Define Channel Name
run: echo "CHANNEL_NAME=${{ github.ref_name }}-${GITHUB_RUN_ID}${GITHUB_RUN_ATTEMPT}" >> $GITHUB_ENV
- name: Package Helm Chart for Replicated
id: package-helm-chart
run: |
helm package relmatrix-app -u -d kots \
--app-version=${{ env.APP_VERSION }} \
--version=${{ env.APP_VERSION }}
- name: Update the HelmChart kind
uses: jacobtomlinson/gha-find-replace@v3
with:
include: 'kots/relmatrix-app-chart.yaml'
find: '$VERSION'
replace: ${{ env.APP_VERSION }}
regex: false
- name: Create Replicated Release
id: create-release
uses: replicatedhq/compatibility-actions/create-release@v1
with:
app-slug: ${{ secrets.REPLICATED_APP }}
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
yaml-dir: ./kots
promote-channel: ${{ env.CHANNEL_NAME }}
version: ${{ env.APP_VERSION }}
compatibility-matrix:
needs: push-to-replicated
strategy:
fail-fast: false
matrix:
cluster: [ {distribution: kind, version: v1.25.3}, {distribution: kind, version: v1.26.3}]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Define App Version
run: echo "APP_VERSION=0.0.1-${GITHUB_REF_NAME//[^a-zA-Z0-9]/}.${GITHUB_RUN_ID}${GITHUB_RUN_ATTEMPT}" >> $GITHUB_ENV
- name: Create Customer
id: create-customer
uses: replicatedhq/compatibility-actions/create-customer@v1
with:
app-slug: ${{ secrets.REPLICATED_APP }}
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
customer-name: ${{ github.ref_name }}-${{ matrix.cluster.distribution }}-${{ matrix.cluster.version }}
channel-slug: ${{ needs.push-to-replicated.outputs.channel-slug }}
customer-email: ${{ github.ref_name }}@example.com
expires-in: 14
- name: Create Cluster
id: create-cluster
uses: replicatedhq/compatibility-actions/create-cluster@v1
with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
kubernetes-distribution: ${{ matrix.cluster.distribution }}
kubernetes-version: ${{ matrix.cluster.version }}
cluster-name: ${{ github.ref_name }}-${{ matrix.cluster.distribution }}-${{ matrix.cluster.version }}
timeout-minutes: 2
ttl: 10m
- name: Deploy the app
uses: replicatedhq/compatibility-actions/helm-install@v1
with:
kubeconfig: ${{ steps.create-cluster.outputs.cluster-kubeconfig }}
helm-path: "helm"
registry-username: ${{ github.ref_name }}@example.com
registry-password: ${{ steps.create-customer.outputs.license-id }}
chart: oci://registry.replicated.com/${{ secrets.REPLICATED_APP }}/${{ needs.push-to-replicated.outputs.channel-slug }}/relmatrix-app
name: 'relmatrix-app'
version: ${{ env.APP_VERSION }}
namespace: 'default'
values: |
image:
tag: latest
- name: Run a test
# mask the kubeconfig so it doesn't show up in the logs
run: |
echo "Running a test"
echo "${{ steps.create-cluster.outputs.cluster-kubeconfig }}" > kubeconfig.yaml
sleep 60
kubectl port-forward svc/relmatrix-app --pod-running-timeout=2m --kubeconfig='./kubeconfig.yaml' 8080:80 &
sleep 120
curl -f http://localhost:8080
echo "Test complete"
- name: Remove Cluster
id: remove-cluster
uses: replicatedhq/compatibility-actions/remove-cluster@v1
continue-on-error: true # It could be that the cluster is already removed
with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
cluster-id: ${{ steps.create-cluster.outputs.cluster-id }}
- name: Archive Customer
id: archive-customer
if: always()
uses: replicatedhq/compatibility-actions/archive-customer@use-channel-slug
with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
customer-id: ${{ steps.create-customer.outputs.customer-id }}
cleanup-channel:
needs:
- compatibility-matrix
- push-to-replicated
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Archive Replicated Channel
uses: replicatedhq/compatibility-actions/archive-channel@v1
with:
app-slug: ${{ secrets.REPLICATED_APP }}
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
channel-slug: ${{ needs.push-to-replicated.outputs.channel-slug }}

Installation with KOTS

See the example workflow for more details.

name: development-kots
on:
push:
branches:
- '*' # matches every branch that doesn't contain a '/'
- '*/*' # matches every branch containing a single '/'
- '**' # matches every branch
- '!main' # excludes main
jobs:
push-to-replicated:
runs-on: ubuntu-22.04
outputs:
channel-slug: ${{ steps.create-release.outputs.channel-slug}}
steps:
- uses: actions/checkout@v3
- name: Define App Version
run: echo "APP_VERSION=0.0.1-${GITHUB_REF_NAME//[^a-zA-Z0-9]/}.${GITHUB_RUN_ID}${GITHUB_RUN_ATTEMPT}" >> $GITHUB_ENV
- name: Define Channel Name
run: echo "CHANNEL_NAME=${{ github.ref_name }}-${GITHUB_RUN_ID}${GITHUB_RUN_ATTEMPT}" >> $GITHUB_ENV
- name: Package Helm Chart for Replicated
id: package-helm-chart
run: |
helm package relmatrix-app -u -d kots \
--app-version=${{ env.APP_VERSION }} \
--version=${{ env.APP_VERSION }}
- name: Update the HelmChart kind
uses: jacobtomlinson/gha-find-replace@v3
with:
include: 'kots/relmatrix-app-chart.yaml'
find: '$VERSION'
replace: ${{ env.APP_VERSION }}
regex: false
- name: Create Replicated Release
id: create-release
uses: replicatedhq/compatibility-actions/create-release@v1
with:
app-slug: ${{ secrets.REPLICATED_APP }}
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
yaml-dir: ./kots
promote-channel: ${{ env.CHANNEL_NAME }}
version: ${{ env.APP_VERSION }}
compatibility-matrix:
needs: push-to-replicated
strategy:
fail-fast: false
matrix:
cluster: [ {distribution: kind, version: v1.25.3}, {distribution: kind, version: v1.26.3}]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Define App Version
run: echo "APP_VERSION=0.0.1-${GITHUB_REF_NAME//[^a-zA-Z0-9]/}.${GITHUB_RUN_ID}${GITHUB_RUN_ATTEMPT}" >> $GITHUB_ENV
- name: Create Customer
id: create-customer
uses: replicatedhq/compatibility-actions/create-customer@v1
with:
app-slug: ${{ secrets.REPLICATED_APP }}
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
customer-name: ${{ github.ref_name }}-${{ matrix.cluster.distribution }}-${{ matrix.cluster.version }}
channel-slug: ${{ needs.push-to-replicated.outputs.channel-slug }}
customer-email: ${{ github.ref_name }}@example.com
expires-in: 14
- name: Create Cluster
id: create-cluster
uses: replicatedhq/compatibility-actions/create-cluster@v1
with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
kubernetes-distribution: ${{ matrix.cluster.distribution }}
kubernetes-version: ${{ matrix.cluster.version }}
cluster-name: ${{ github.ref_name }}-${{ matrix.cluster.distribution }}-${{ matrix.cluster.version }}
timeout-minutes: 2
ttl: 10m
- name: Deploy the app
uses: replicatedhq/compatibility-actions/kots-install@v1
with:
kubeconfig: ${{ steps.create-cluster.outputs.cluster-kubeconfig }}
app-slug: ${{ secrets.REPLICATED_APP }}/${{ needs.push-to-replicated.outputs.channel-slug }}
license-file: ${{ steps.create-customer.outputs.license-file }}
app-version-label: ${{ env.APP_VERSION }}
- name: Run a test
# mask the kubeconfig so it doesn't show up in the logs
run: |
echo "Running a test"
echo "${{ steps.create-cluster.outputs.cluster-kubeconfig }}" > kubeconfig.yaml
sleep 60
kubectl port-forward svc/relmatrix-relmatrix-app --pod-running-timeout=2m --kubeconfig='./kubeconfig.yaml' 8080:80 &
sleep 120
curl -f http://localhost:8080
echo "Test complete"
- name: Remove Cluster
id: remove-cluster
uses: replicatedhq/compatibility-actions/remove-cluster@v1
continue-on-error: true # It could be that the cluster is already removed
with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
cluster-id: ${{ steps.create-cluster.outputs.cluster-id }}
- name: Archive Customer
id: archive-customer
if: always()
uses: replicatedhq/compatibility-actions/archive-customer@use-channel-slug
with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
customer-id: ${{ steps.create-customer.outputs.customer-id }}
cleanup-channel:
needs:
- compatibility-matrix
- push-to-replicated
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Archive Replicated Channel
uses: replicatedhq/compatibility-actions/archive-channel@v1
with:
app-slug: ${{ secrets.REPLICATED_APP }}
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
channel-slug: ${{ needs.push-to-replicated.outputs.channel-slug }}

Releasing

The releasing workflow will run the workflow each time a tag is being placed on the repository. It will create a new release that is promoted to a channel with the same name as the tag. The next job will setup a compatibility matrix of clusters, deploy the app and execute some tests. Once everything is successful the release will be promoted to the stable channel. And the created clusters and customers for the compatibility matrix will be removed again.

See the example workflow for more details.

name: release
on:
push:
tags:
- "v*.*.*"
jobs:
push-to-replicated:
runs-on: ubuntu-22.04
outputs:
channel-slug: ${{ steps.create-release.outputs.channel-slug}}
release-sequence: ${{ steps.create-release.outputs.release-sequence}}
steps:
- uses: actions/checkout@v3
- name: Define Channel Name
run: echo "CHANNEL_NAME=${{ github.ref_name }}-${GITHUB_RUN_ID}${GITHUB_RUN_ATTEMPT}" >> $GITHUB_ENV
- name: Package Helm Chart for Replicated
id: package-helm-chart
run: |
helm package relmatrix-app -u -d kots \
--app-version=${{ github.ref_name }} \
--version=${{ github.ref_name }}
- name: Update the HelmChart kind
uses: jacobtomlinson/gha-find-replace@v3
with:
include: 'kots/relmatrix-app-chart.yaml'
find: '$VERSION'
replace: '${{ github.ref_name }}'
regex: false
- name: Create Replicated Release
id: create-release
uses: replicatedhq/compatibility-actions/create-release@v0
with:
app-slug: ${{ secrets.REPLICATED_APP }}
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
yaml-dir: ./kots
promote-channel: ${{ env.CHANNEL_NAME }}
version: ${{ github.ref_name }}
compatibility-matrix:
needs: push-to-replicated
strategy:
fail-fast: false
matrix:
cluster: [ {distribution: kind, version: v1.25.3}, {distribution: kind, version: v1.26.3}]
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Create Customer
id: create-customer
uses: replicatedhq/compatibility-actions/create-customer@v0
with:
app-slug: ${{ secrets.REPLICATED_APP }}
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
customer-name: ${{ github.ref_name }}-${{ matrix.cluster.distribution }}-${{ matrix.cluster.version }}
channel-slug: ${{ needs.push-to-replicated.outputs.channel-slug }}
customer-email: ${{ github.ref_name }}@example.com
expires-in: 14
- name: Create Cluster
id: create-cluster
uses: replicatedhq/compatibility-actions/create-cluster@v0
with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
kubernetes-distribution: ${{ matrix.cluster.distribution }}
kubernetes-version: ${{ matrix.cluster.version }}
cluster-name: ${{ github.ref_name }}-${{ matrix.cluster.distribution }}-${{ matrix.cluster.version }}
timeout-minutes: 2
ttl: 10m
- name: Deploy the app
uses: replicatedhq/compatibility-actions/helm-install@v0
with:
kubeconfig: ${{ steps.create-cluster.outputs.cluster-kubeconfig }}
helm-path: "helm"
registry-username: ${{ github.ref_name }}@example.com
registry-password: ${{ steps.create-customer.outputs.license-id }}
chart: oci://registry.replicated.com/${{ secrets.REPLICATED_APP }}/${{ needs.push-to-replicated.outputs.channel-slug }}/relmatrix-app
name: 'relmatrix-app'
version: ${{ github.ref_name }}
namespace: 'default'
values: |
image:
tag: latest
- name: Run a test
# mask the kubeconfig so it doesn't show up in the logs
run: |
echo "Running a test"
echo "${{ steps.create-cluster.outputs.cluster-kubeconfig }}" > kubeconfig.yaml
sleep 60
kubectl port-forward svc/relmatrix-app --pod-running-timeout=2m --kubeconfig='./kubeconfig.yaml' 8080:80 &
sleep 120
curl -f http://localhost:8080
echo "Test complete"
- name: Remove Cluster
id: remove-cluster
uses: replicatedhq/compatibility-actions/remove-cluster@v0
continue-on-error: true # It could be that the cluster is already removed
with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
cluster-id: ${{ steps.create-cluster.outputs.cluster-id }}
- name: Archive Customer
id: archive-customer
if: always()
uses: replicatedhq/compatibility-actions/archive-customer@use-channel-slug
with:
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
customer-id: ${{ steps.create-customer.outputs.customer-id }}
promote-to-stable:
needs:
- compatibility-matrix
- push-to-replicated
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Promote to Stable channel
uses: replicatedhq/compatibility-actions/promote-release@v0
with:
app-slug: ${{ secrets.REPLICATED_APP }}
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
channel-to: stable
release-sequence: ${{ needs.push-to-replicated.outputs.release-sequence }}
release-version: ${{ github.ref_name }}
cleanup-channel:
needs:
- promote-to-stable
- push-to-replicated
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- name: Archive Replicated Channel
uses: replicatedhq/compatibility-actions/archive-channel@v0
with:
app-slug: ${{ secrets.REPLICATED_APP }}
api-token: ${{ secrets.REPLICATED_API_TOKEN }}
channel-slug: ${{ needs.push-to-replicated.outputs.channel-slug }}

Secrets and Pull Requests in GitHub Actions

Because these actions require use of the Replicated API token--commonly provided in a repository secret--it is important to understand some of the intrinsic details of how GitHub Actions treats secrets in certain scenarios.

A common use case for integrating GitHub Actions with Replicated may be during the pull request (PR) process. For example, you may choose to build a GitHub Action which creates a cluster and runs any number of tests in a Replicated environment when a PR is sent to your repository. By default, GitHub does not allow access to repository secrets when an Action is triggered from a remote fork because the fork is considered untrustworthy. See the note in the GitHub documentation here. In the case of Replicated's GitHub actions, since the API token is a required input, if the secret cannot be loaded the workflow step which invokes the Replicated API will fail.

In order to provide a secure experience, we recommend the following process.

  1. Use workflow approvals to prevent Actions from firing by default unless approved by a repository user with write access. See the GitHub documentation here for more information.
  2. Carefully inspect the PR prior to approving workflows to run.
  3. Use the pull_request_target trigger in the Action which calls the Replicated service along with the status which should trigger the workflow. An example snippet is shown below. Note that this is only required if an Action which uses a Replicated step must fire on a PR from a fork as described previously.

For further reading on security in GitHub Actions, see this three-part blog series which goes into further depth.

Action Examples

In this below snippet, the pull_request_target trigger is used in one of four possible states which serves to invoke an Action which uses a Replicated step. Use of the more common pull_request trigger is preferred if such an Action does not need to be invoked upon PRs from forks.

name: Replicated demo
on:
  pull_request_target:
    types: [opened, synchronize, reopened, ready_for_review]