NashTech Blog

Zero-Cost Slack-to-GitLab CI/CD Trigger: A Complete Guide

Table of Contents

How we built a serverless system that lets my team trigger tests by simply typing “test” in Slack – without spending a penny.

The Problem: Manual Test Triggers Are Annoying

Imagine this: You’re in the middle of a Slack conversation about a new feature, someone asks, “Can we run the tests to make sure this works?” and suddenly everyone has to:

  • Switch to GitLab
  • Navigate to the CI/CD section
  • Manually trigger a pipeline
  • Switch back to Slack to share the results

There had to be a better way. What if we could just type test In Slack and have it automatically trigger our GitLab pipelines?

That’s exactly what we built, and the best part? It costs absolutely nothing to run.

Slack as a CI/CD Command Centre

We wanted to create something where anyone on the team could trigger different types of tests directly from Slack:

test                    → Run all tests
test unit              → Run only unit tests  
test e2e production    → Run E2E tests on production
test integration branch develop → Run integration tests on develop branch

And get instant feedback:

Tests triggered by @john!
- Suite: unit
- Environment: staging
- Branch: develop  
- Pipeline: https://gitlab.com/project/pipelines/12345

The Architecture: Simple but Powerful

Here’s the flow we designed:

Slack Message → Slack Event → Vercel Function → GitLab API → Pipeline Runs → Slack Notification

Why this stack?

  • Slack: Where our team already communicates
  • Vercel: Free serverless functions with great developer experience
  • GitLab: Our existing CI/CD platform
  • GitHub: Free hosting for the function code

Total monthly cost: $0

Part 1: Setting Up the GitLab Foundation

Creating Pipeline Triggers

First, we needed a way for external services to trigger GitLab pipelines. GitLab has a great feature called “Pipeline Triggers” for exactly this.

Steps to be followed:

  • Went to the GitLab project → Settings → CI/CD
  • Expanded “Pipeline triggers”
  • Created a new trigger with description “Slack integration”
  • Copied the generated token (starts with glptt-)

Note down your Project ID too – it’s the number shown under your project name.

Designing the CI/CD Pipeline

We wanted our pipeline to only run when triggered from Slack, not on every commit. Here’s the YAML we created:

# .gitlab-ci.yml
image: alpine:latest

stages:
  - test

slack_test:
  stage: test
  rules:
    # Only run when triggered via Slack
    - if: $CI_PIPELINE_SOURCE == "trigger" && $TRIGGERED_BY_SLACK == "true"
  before_script:
    - apk add --no-cache curl
  script:
    - echo "Pipeline triggered by Slack user: $SLACK_USER"
    - echo "Test suite: $TEST_SUITE" 
    - echo "Environment: $TEST_ENVIRONMENT"
    - sleep 5  # Simulate test execution
    - echo "Test completed successfully"
  after_script:
    # Post results back to Slack
    - 'curl -X POST -H "Authorization: Bearer $SLACK_BOT_TOKEN" 
        -H "Content-Type: application/json" 
        --data "{\"channel\": \"$SLACK_CHANNEL\", \"text\": \"Pipeline completed! Triggered by <@$SLACK_USER>\"}"'

Key learnings:

  • The rules section ensures this only runs on API triggers, not commits
  • Environment variables like $SLACK_USER get passed from the Slack function
  • The after_script posts results back to Slack, creating a complete feedback loop

Part 2: Building the Slack App

Creating the App

Building a Slack app was straightforward:

Configuring Permissions

The app needs specific permissions to read messages and post responses:

Bot Token Scopes we added:

  • channels:history – Read messages in channels
  • chat:write – Post messages back to channels
  • users:read – Get user information for @mentions

After adding scopes, you must reinstall the app in your workspace for changes to take effect.

Getting the Tokens

Two critical pieces of information:

  • Bot User OAuth Token (starts with xoxb-) – For posting messages
  • Signing Secret – For verifying requests actually come from Slack

We stored these safely for the next step.

Part 3: The Serverless Function

This is where it gets interesting. We needed a webhook that could:

  • Receive Slack events
  • Parse test commands
  • Trigger GitLab pipelines
  • Handle errors gracefully

Choosing Vercel

Why Vercel over AWS Lambda or other options?

  • Free tier is generous (100GB bandwidth/month)
  • Zero configuration deployment from GitHub
  • Excellent developer experience
  • Built-in environment variable management

The Function Structure

We organised the code into clear responsibilities:

// Command parsing - turns "test unit staging" into structured data
function parseTestCommand(message) {
  const text = message.toLowerCase().trim();
  
  // Check if it's a test command
  const testTriggers = ['test', 'run test', 'run tests'];
  const isTestCommand = testTriggers.some(trigger => text.includes(trigger));
  
  if (!isTestCommand) return null;
  
  // Parse test suite, environment, branch
  // Returns: { testSuite: 'unit', environment: 'staging', branch: 'main' }
}

// GitLab integration - triggers the actual pipeline
async function triggerGitLabTests(testConfig, slackUser, slackChannel) {
  const variables = {
    TRIGGERED_BY_SLACK: 'true',
    SLACK_USER: slackUser,
    SLACK_CHANNEL: slackChannel,
    TEST_SUITE: testConfig.testSuite,
    TEST_ENVIRONMENT: testConfig.environment
  };
  
  // Call GitLab's trigger API
  const response = await fetch(
    `${GITLAB_URL}/api/v4/projects/${GITLAB_PROJECT_ID}/trigger/pipeline`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        token: GITLAB_TRIGGER_TOKEN,
        ref: testConfig.branch,
        variables
      })
    }
  );
  
  return await response.json();
}

Security: Verifying Slack Requests

One crucial security measure, verifying that requests actually come from Slack:

function verifySlackRequest(req) {
  const signature = req.headers['x-slack-signature'];
  const timestamp = req.headers['x-slack-request-timestamp'];
  const body = JSON.stringify(req.body);
  
  const hmac = crypto.createHmac('sha256', SLACK_SIGNING_SECRET);
  const [version, hash] = signature.split('=');
  hmac.update(`${version}:${timestamp}:${body}`);
  
  return hmac.digest('hex') === hash;
}

This prevents malicious actors from triggering your pipelines.

Part 4: Deployment and Configuration

GitHub to Vercel Pipeline

We set up automatic deployment:

  • Created a public GitHub repository (required for free Vercel tier)
  • Connected Vercel to the repository
  • Every push to main automatically deploys

File structure:

slack-gitlab-bridge/
├── api/
│   └── slack-event.js    # The serverless function
├── package.json          # Node.js configuration  
├── vercel.json          # Vercel settings
└── README.md

Environment Variables

All the secrets go into Vercel’s environment variables:

SLACK_SIGNING_SECRET=abc123...
SLACK_BOT_TOKEN=xoxb-123-456...
GITLAB_PROJECT_ID=74168798
GITLAB_TRIGGER_TOKEN=glptt-def456...
GITLAB_URL=https://gitlab.com

No secrets in the code repository!

Connecting Slack to Vercel

The final piece, telling Slack where to send events:

  • In Slack app settings → Event Subscriptions
  • Request URL: https://my-app.vercel.app/api/slack-event
  • Subscribe to message.channels events

Slack sends a verification challenge, and our function handles it:

if (req.body?.type === 'url_verification') {
  return res.json({ challenge: req.body.challenge });
}

That’s it, just type “test” in your specified Slack channel, and you are good to go.

Conslusion

The best part: Watching team members naturally start running tests more often because it became so easy. Sometimes the best productivity improvements are the ones that remove friction from workflows people already want to follow.

The complete code and step-by-step guide are available on GitHub. Feel free to reach out if you have questions or build something cool with this approach!

Tech Stack: Slack API, Vercel Serverless Functions, GitLab CI/CD, JavaScript/Node.js
Cost: $0/month
Setup Time: ~2 hours
Maintenance: Minimal

Picture of Sparsh Bhardwaj

Sparsh Bhardwaj

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top