</>

Technology

GitHub Actions

Difficulty

Beginner

Interview Question

What are jobs and steps in GitHub Actions? How do jobs depend on each other?

Answer

Jobs and Steps in GitHub Actions

Jobs — Parallel Units of Work

By default, all jobs run in parallel. Each job gets its own fresh runner.

YAML
name: CI Pipeline
on: push

jobs:
  build:          # ← Job 1
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building..."

  test:           # ← Job 2 (runs IN PARALLEL with build by default)
    runs-on: ubuntu-latest
    steps:
      - run: echo "Testing..."

  lint:           # ← Job 3 (also runs in parallel)
    runs-on: ubuntu-latest
    steps:
      - run: echo "Linting..."

needs: — Job Dependencies (Sequential)

YAML
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: mvn clean package -DskipTests

  test:
    needs: build          # ← waits for build to succeed
    runs-on: ubuntu-latest
    steps:
      - run: mvn test

  deploy:
    needs: [build, test]  # ← waits for BOTH build AND test
    runs-on: ubuntu-latest
    steps:
      - run: ./deploy.sh

  notify:
    needs: deploy         # ← runs after deploy
    if: always()          # ← runs even if deploy failed
    runs-on: ubuntu-latest
    steps:
      - run: echo "Sending notification..."

Steps — Sequential Tasks Inside a Job

Steps run one after another in the order defined. If a step fails, subsequent steps are skipped by default.

YAML
jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      # Step 1: Checkout repo
      - name: Checkout code
        uses: actions/checkout@v4

      # Step 2: Set up Java
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      # Step 3: Cache Maven dependencies
      - name: Cache Maven packages
        uses: actions/cache@v4
        with:
          path: ~/.m2
          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}

      # Step 4: Run tests
      - name: Run TestNG tests
        run: mvn test -Dbrowser=chrome -Denv=staging

      # Step 5: Always upload report (even if tests fail)
      - name: Upload test report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-report
          path: target/surefire-reports/

Step Conditions (if:)

YAML
steps:
  - name: Run tests
    run: mvn test

  - name: Upload on failure only
    if: failure()           # only if previous step failed
    uses: actions/upload-artifact@v4
    with:
      name: failure-screenshots
      path: screenshots/

  - name: Deploy on main branch only
    if: github.ref == 'refs/heads/main' && success()
    run: ./deploy.sh

  - name: Always notify
    if: always()            # success OR failure
    run: echo "Done"

Pass Data Between Steps Using outputs

YAML
jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.get-version.outputs.version }}

    steps:
      - id: get-version
        run: |
          VERSION=$(mvn help:evaluate -q -Dexpression=project.version -DforceStdout)
          echo "version=$VERSION" >> $GITHUB_OUTPUT

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying version ${{ needs.build.outputs.version }}"

Follow AutomateQA

Related Topics