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.
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 |
See the example workflow for more details.
replicated-actions/example-workflows/development-helm.yaml
Lines 1 to 140 in 71c3cdf
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 }} |
See the example workflow for more details.
replicated-actions/example-workflows/development-kots.yaml
Lines 1 to 133 in 71c3cdf
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 }} |
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.
replicated-actions/example-workflows/release.yaml
Lines 1 to 151 in 71c3cdf
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 }} | |
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.
- 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.
- Carefully inspect the PR prior to approving workflows to run.
- 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.
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]