Migrate from GitHub Actions to Harness CI
Harness CI and GitHub Actions both allow you to create workflows that automatically build, test, publish, release, and deploy code.
Harness does not require scripting, and configurations are passed to pipelines securely and pragmatically. In contrast, GitHub Actions provides third-party actions that you use with semi-plug-and-play functionality.
What makes Harness CI unique?
Harness CI provides proprietary technologies, like Cache Intelligence and Test Intelligence, that make Harness CI four times faster than other leading CI tools.
- Harness Test Intelligence (TI) is a proprietary technology that accelerates test cycles by running only the tests necessary to confirm the quality of the code changes that triggered a build. Visualizations show which code changes caused which tests to be selected, and TI can help you identify gaps in your test plan. TI also detects negative trends and provides actionable insights to improve quality. With TI, it's possible to reduce build cycle times by up to 90% without compromising application quality.
- Harness Cache Intelligence is a proprietary technology that reduces pipeline execution time by automatically caching well-known directories for languages like Java and Node.js.
Harness CI is part of The Harness Platform, which is a self-service CI/CD platform that enables end-to-end software delivery. The Harness Platform includes features, functionality, and additional modules to help you build, test, deploy, and verify software. For example:
- Role-Based Access Control (RBAC) helps you control user and group access to Harness resources according to users' roles. Using RBAC increases security and improves efficiency.
- Harness Policy as Code is a centralized policy management and rules service that leverages the Open Policy Agent (OPA) to meet compliance requirements across software delivery and enforce governance policies.
- The Harness Enterprise Ready Self-Managed Edition is an end-to-end solution for continuous, self-managed delivery. You can install and update Harness Self-Managed Enterprise Edition using online or offline (air-gapped) methods.
GitHub Actions plugins
Harness CI offers built-in support for GitHub Actions. You can use the GitHub Action step in pipelines that use Harness Cloud build infrastructure. For other build infrastructures, you can use the GitHub Actions Drone plugin in a Plugin step.
Other advantages
Harness CI offers the following additional advantages over GitHub Actions:
- Harness offers a variety of build infrastructure options, including Apple silicon and Linux arm64 options.
- Harness supports both Terraform and CloudFormation infrastructure provisioning with simpler structures and configurations than their corresponding GitHub Actions.
- GitHub Actions does not provide a native Accelerate metrics dashboard, whereas Harness offers both a dedicated dashboard and the ability to configure alerts.
Comparison: Workflow architecture
Both Harness CI and GitHub Actions use workflows to organize builds. In Harness CI, these workflows are called pipelines. In both products, workflows are divided into major segments, which are called stages in Harness CI and jobs in GitHub Actions. Each stage or job includes one or more steps or individual commands.
In GitHub Actions, if a job has a lot of steps, those steps might be organized into groups, which are called stages. Similarly, in Harness CI, you can use step groups to group steps within a stage.
The following truncated examples provide a simple comparison of stage and step structure in GitLab CI and Harness CI.
- GitHub Actions
- Harness
jobs:
job_1:
name: job_1
runs-on: ubuntu-latest
steps:
- name: compile code
container:
image: python:3.10.6-alpine
run: |
python -m compileall ./
stages:
- stage:
name: stage1
...
spec:
...
platform:
os: Linux
arch: Amd64
...
execution:
steps:
- step:
type: Run
name: compile code
identifier: compile_code
spec:
connectorRef: myDockerHubConnector
image: python:3.10.6-alpine
shell: Sh
command: python -m compileall ./
For more information about Harness terminology, features, and pipeline components, go to the CI key concepts.
Both Harness CI and GitHub Actions workflows are written in YAML. Whereas GitHub Actions workflow configurations are always stored in the .github/workflows
directory in your code repo, Harness provides you a choice of inline pipeline storage or importing pipelines from Git. Harness also provides both visual and code-based pipeline editors.
- The Harness YAML editor includes schema validation and auto-complete recommendations to simplify and expedite pipeline configuration.
- The Harness visual editor provides a guided experience that enables anyone to easily build, debug, and run pipelines.
- You can switch back and forth between editors.
Complete workflow comparison
Here are YAML examples of complete workflows in GitHub Actions and Harness CI.
- GitHub Actions
- Harness
name: Github_actions
on:
pull_request:
branches:
- main
jobs:
job_1:
name: job_1
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: login to docker hub
uses: docker/login-action@v2
with:
username: {{secrets.DOCKERHUB_USERNAME}}
password: {{secrets.DOCKERHUB_TOKEN}}
- name: step_1
container:
image: openjdk:17.0-jdk
run: |
echo "this runs on openjdk"
services:
postgres:
image: postgres:10.8
env:
POSTGRES_USER: postgres
POSTGRES_DB: postgres
POSTGRES_PASSWORD: ""
job_2:
name: job_2
runs-on: ubuntu-latest
steps:
- name: step_2
container:
image: node:13.0.0
run: |
echo "pipeline var:" $pipeline_var
echo "project level var:" $project_var
echo "secret example :" ${{ secrets.Db_Password)}}
job_3:
name: job_3
runs-on: ubuntu-latest
strategy:
matrix:
version: ["node","python","ubuntu"]
steps:
- name: matrix
run: |
echo "Testing on ${{ matrix.version }}
pipeline:
name: gha-test
identifier: ghatest
projectIdentifier: gha_test
orgIdentifier: default
tags: {}
properties:
ci:
codebase:
connectorRef: account.myscm
repoName: test
build: <+input>
stages:
- stage:
name: stage1
identifier: stage1
description: ""
type: CI
spec:
cloneCodebase: true
platform:
os: Linux
arch: Amd64
runtime:
type: Cloud
spec: {}
execution:
steps:
- step:
type: Background
name: postgres-dependency
identifier: postgresdependency
spec:
connectorRef: myDockerHubConnector
image: postgres:10.8
shell: Sh
envVariables:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: <+secrets.getValue("DbPasswordSecret")>
POSTGRES_DB: postgres
- step:
type: Run
name: Run_1
identifier: Run_1
spec:
connectorRef: myDockerHubConnector
image: openjdk:17.0-jdk
shell: Bash
command: echo "this runs on openjdk"
- stage:
name: stage2
identifier: stage2
description: ""
type: CI
spec:
cloneCodebase: true
execution:
steps:
- step:
type: Run
name: Run_2
identifier: Run_2
spec:
connectorRef: myDockerHubConnector
image: node:13.0.0
shell: Bash
command: |-
echo "pipeline var:" <+pipeline.variables.pipelinevar1>
echo "project level var:" <+variable.proj_var>
echo "secret example :" <+secrets.getValue("DbPasswordSecret")>
platform:
os: Linux
arch: Amd64
runtime:
type: Cloud
spec: {}
- stage:
name: matrix stage
identifier: matrix_stage
description: ""
type: CI
spec:
cloneCodebase: true
platform:
os: Linux
arch: Amd64
runtime:
type: Cloud
spec: {}
execution:
steps:
- step:
type: Run
name: Run_3
identifier: Run_3
spec:
shell: Bash
command: echo "Testing on <+matrix.testparam>"
strategy:
matrix:
testparam:
- node
- python
- ubuntu
maxConcurrency: 3
variables:
- name: pipelinevar1
type: String
description: ""
value: someval
Steps run as the root user, generally. For example, with Harness Cloud build infrastructure, steps run directly on the host and, therefore, run as the root user.
For services running on containers (which are steps where you specify a Container Registry and Image to use to execute the step's commands), you can use the Run as User setting to specify a user to use for that container.
With Kubernetes cluster build infrastructure, you can use the Run as User setting to specify a user to use for individual steps, or you can set a default user for all steps and then override the default user as needed for individual steps.
Comparison: Clone a codebase
- GitHub Actions
- Harness
GitHub Actions workflows are inherently associated with a code repo because the workflow YAML exists in the .github/workflows
directory in the target code repo. The workflow can use actions/checkout in a step to clone the associated codebase into the workflow workspace.
name: Github_actions
on:
pull_request:
branches:
- main
jobs:
job_1:
name: job_1
...
steps:
- name: Checkout code
uses: actions/checkout@v2
In Harness CI, each pipeline has a codebase specification that identifies the code repo (input) that the pipeline uses to build an artifact (output). Codebase configuration has two components:
- The codebase connector, such as a GitHub connector, that specifies the codebase URL and required credentials to access your code repos.
- A series of settings describing how you want the pipeline to clone and build the repo.
When you create a Harness CI pipeline, you specify a default codebase to use for all stages in the pipeline. By default, each stage automatically clones the designated code repo from your Git provider into the stage's build infrastructure when the pipeline runs.
pipeline:
...
codebase:
connectorRef: account.myscm ## Codebase connector ID.
repoName: test ## A repo name. If set to <+input>, you can specify a repo when the pipeline runs.
build: <+input> ## This value means you'll specify the branch to pull when the pipeline runs.
stages:
- stage:
name: stage1
...
spec:
cloneCodebase: true ## Indicates that this stage will clone the pipeline's default codebase. If set to false, the stage won't clone the codebase.
Harness integrates with many different types of repositories and providers. A connection from Harness to other platforms is called a connector. Connectors can connect to source control providers, cloud providers, container registries, and more.
In addition to codebase configuration, you can also use connectors in individual steps to specify Docker images or even clone additional codebases in the same pipeline.
For example, in the following YAML example, the connectorRef
references a Docker connector. Docker connectors are platform-agnostic and can be used to connect to any Docker container registry.
- step:
type: Run
name: step1
identifier: step1
spec:
connectorRef: my-dockerhub-connector
image: openjdk:17.0-jdk
shell: Bash
command: echo "this runs on openjdk"
Comparison: Access Docker
- GitHub Actions
- Harness
To log in to Docker Hub in a GitHub Actions workflow, you use docker/login-action
in a step. You then use other docker
actions in other steps to pull images, push images, and so on.
name: login to docker hub
uses: docker/login-action@v2
with:
username: {{ secrets.DOCKERHUB_USERNAME }}
password: {{ secrets.DOCKERHUB_TOKEN }}
name: build and push docker image
uses: docker/build-push-action@v3
with:
context:
file: ./pythondockerfile
push: true
tags: user/pythonsample:latest
To interact with Docker registries in Harness, you use a Docker connector. In the following YAML example, the connectorRef
references a Docker connector and the image
indicates the image to pull. You do not need an extra step to connect to Docker - Harness handles the login/connection through the connector configuration.
- step:
type: Run
name: step1
identifier: step1
spec:
connectorRef: my-docker-hub-connector
image: openjdk:17.0-jdk
shell: Bash
command: echo "this runs on openjdk"
In the previous example, a Docker connector was used to pull an image for a script. You can also use Docker connectors to do other Docker-related actions, such as building and pushing images to Docker registries.
- step:
type: BuildAndPushDockerRegistry
name: build and push to the docker registry
identifier: build_and_push_to_the_docker_registry
spec:
connectorRef: myDockerConnector
repo: myrepo/pythonsample
tags:
- latest
dockerfile: pythondockerfile
Comparison: Environment variables
In GitHub Actions, you can use predefined environment variables, define custom variables within a single workflow, or define custom variables at the organization, account, and environment levels. You can use predefined environment variables or define custom variables.
This range of variable definition is also possible in Harness CI. In addition to built-in variables, you can define variables within individual pipelines, stages, and steps as well as at the project, organization, and account levels.
- GitHub Actions
- Harness
This GitHub Actions example defines environment variables at the workflow and job levels.
env:
ENV_VAR: value1
jobs:
job_1:
runs-on: ubuntu-latest
env:
JOB_VAR: value2
steps:
- name: simple script
run: echo "$JOB_VAR $ENV_VAR"
To reference project, organization, and account variables, you use variable expressions formatted as: <+variable.[scope].[variable_id]>
. Here are the syntax formats for variables declared at different levels:
- Account-level variable reference:
<+variable.account.[var_id]>
- Organization-level variable reference:
<+variable.org.[var_id]>
- Project-level variable reference:
<+variable.[var_id]>
In this example, a step references a project-level environment variable called ENV_VAR
.
- step:
type: Run
name: test-variable
identifier: test_variable
spec:
command: echo "environment variable: " <+variable.env_var>
Within a single pipeline, you can define variables at the step, stage, and pipeline levels. For example, this step includes environment variable definitions.
- step:
type: Background
name: Background_1
identifier: Background_1
spec:
connectorRef: account.harnessImage
image: postgres:10.8
envVariables:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: <+secrets.getValue("DbPasswordSecret")>
POSTGRES_DB: postgres
To learn more about defining and fetching variables go to:
Comparison: Matrix jobs
In both Harness CI and GitHub Actions, you can define matrix strategies for your jobs to iterate over a series of inputs. In both products, you define a matrix strategy and then call the strategy by it's tag or other identifier when you want to use it in a command or step.
In Harness, matrix looping strategies are one of several looping execution strategies. To learn about the looping strategies available in Harness, go to Use looping strategies
- GitHub Actions
- Harness
jobs:
example_matrix:
strategy:
matrix:
testparam: [node, python, ubuntu]
steps:
- name: simple script
run: echo "Testing on ${{ matrix.testparam }}"
The following example describes a stage in a Harness CI pipeline that includes one step with matrix and parallelism strategies. The looping strategies are defined in strategy
at the stage level. One matrix strategy, called testparam
, is defined in matrix
and parallelism is defined by maxConcurrency: 3
. The script in the Run
step calls the inputs from the matrix strategy by using the expression +matrix.testparam>
.
stages:
- stage:
name: Stage1
...
steps:
- step:
type: Run
name: step1
identifier: step1
spec:
shell: Bash
command: echo "Testing on <+matrix.testparam>"
strategy:
matrix:
testparam:
- node
- python
- ubuntu
maxConcurrency: 3
Comparison: Triggers
In GitHub Actions, triggers are defined in the workflow based on Git events against specified branches or conditions.
Harness CI supports webhook, artifact, manifest and schedule triggers. The two most commonly used triggers are webhook triggers based on Git events and scheduled triggers based on cron
expressions. To learn more about creating triggers, go to:
- GitHub Actions
- Harness
This GitHub Actions trigger listens for specific words in the name of pull requests against the main
branch.
on:
pull_request:
branches:
- main
jobs:
gobuild:
if: contains(github.event.pull_request.labels.*.name, 'go') || contains(github.event.pull_request.labels.*.name, 'gojava')
This Harness CI example shows a cron
trigger on the main
branch.
trigger:
name: trigger
identifier: trigger
enabled: true
orgIdentifier: default
projectIdentifier: UNIQUE_IDENTIFIER
pipelineIdentifier: Project_Name
source:
type: Scheduled
spec:
type: Cron
spec:
expression: 45 13 13 09 2
inputYaml: |
pipeline:
identifier: Project_Name
properties:
ci:
codebase:
build:
type: branch
spec:
branch: main
See also
Review the following information before proceeding with migration: