Create Slack channel for Incident Management
Overviewโ
Streamline incident response with this self-service action. It automatically creates dedicated Slack channels for your services, optionally adding key team members during setup.
- Faster Incident Response: Instantly create communication channels when issues arise.
- Consistent Process: Ensure standard channel naming and member inclusion.
- Developer Self-Service: Empower teams to create incident channels without needing extra Slack permissions.
- Reduced Manual Steps: Automate a routine task, freeing up time for your team.
Prerequisitesโ
- 
Port's GitHub app needs to be installed. 
- 
Setup Slack App: - Create a slack app and install it on a workspace.
- Add the following permissions to the slack app:
- Create channel (Required) :
channels:managegroups:writeim:writempim:write
- Find a user with an email address (Optional) :
users:read.email
- Invite users to channel (Optional) :
channels:write.invitesgroups:write.invitesmpim:write.invites
 
- Create channel (Required) :
 warningWithout scopes for Find a user with an email addressandInvite users to channel, the channel will be created but users will not be added to it.- Then install the app in your slack workspace.
- Navigate back to the OAuth & Permissions page. You'll see an access token under OAuth Tokens for Your Workspace that you will use in the BOT_USER_OAUTH_TOKENGitHub secret.
 
   
- 
In your GitHub repository, go to Settings > Secrets and add the following secrets: - BOT_USER_OAUTH_TOKEN- Slack Bot User Oauth Token generated for the slack app.
- PORT_CLIENT_ID- Your port client id.
- PORT_CLIENT_SECRET- Your port client secret.
 
- 
Create a service blueprint with the following JSON definition: 
Service Blueprint (Click to expand)
{
  "identifier": "service",
  "title": "Service",
  "icon": "Github",
  "teamInheritance": {
    "path": "team"
  },
  "schema": {
    "properties": {
      "readme": {
        "title": "README",
        "type": "string",
        "format": "markdown",
        "icon": "Book"
      },
      "language": {
        "icon": "Git",
        "type": "string",
        "title": "Language",
        "enum": ["GO", "Python", "Node", "React"],
        "enumColors": {
          "GO": "red",
          "Python": "green",
          "Node": "blue",
          "React": "yellow"
        }
      },
      "tier": {
        "icon": "DefaultProperty",
        "title": "Tier",
        "description": "Service Tiers indicate the significance or importance of a Service for business operations",
        "type": "string",
        "enum": [
          "Mission Critical",
          "Customer Facing",
          "Internal Service",
          "Other"
        ],
        "enumColors": {
          "Mission Critical": "turquoise",
          "Customer Facing": "green",
          "Internal Service": "darkGray",
          "Other": "yellow"
        }
      },
      "code_owners": {
        "title": "Code owners",
        "description": "This service's code owners",
        "type": "array",
        "icon": "TwoUsers"
      },
      "resource_definitions": {
        "title": "Resource definitions",
        "description": "A link to the service's resource definitions",
        "icon": "Terraform",
        "type": "string",
        "format": "url"
      },
      "type": {
        "title": "Type",
        "description": "This service's type",
        "type": "string",
        "enum": ["Backend", "Frontend", "Library"],
        "enumColors": {
          "Backend": "purple",
          "Frontend": "pink",
          "Library": "green"
        },
        "icon": "DefaultProperty"
      },
      "lifecycle": {
        "title": "Lifecycle",
        "type": "string",
        "enum": ["Production", "Experimental", "Deprecated"],
        "enumColors": {
          "Production": "green",
          "Experimental": "yellow",
          "Deprecated": "red"
        },
        "icon": "DefaultProperty"
      },
      "require_approval_count": {
        "title": "Require approvals",
        "type": "number",
        "icon": "DefaultProperty"
      },
      "is_protected": {
        "title": "Is branch protected",
        "type": "boolean",
        "icon": "DefaultProperty"
      },
      "require_code_owner_review": {
        "title": "Require code owner review",
        "type": "boolean",
        "icon": "DefaultProperty"
      },
      "locked_in_prod": {
        "icon": "DefaultProperty",
        "title": "Locked in Prod",
        "type": "boolean",
        "default": false
      },
      "last_push": {
        "icon": "GitPullRequest",
        "title": "Last push",
        "description": "Last commit to the main branch",
        "type": "string",
        "format": "date-time"
      },
      "required_approvals": {
        "icon": "Lock",
        "title": "Required approvals",
        "type": "number",
        "description": "Number of required approvals for a PR to be merged to main branch"
      },
      "locked_reason_prod": {
        "icon": "DefaultProperty",
        "title": "Locked Reason Prod",
        "type": "string"
      },
      "locked_reason_test": {
        "title": "Locked Reason Test",
        "type": "string",
        "icon": "DefaultProperty"
      },
      "locked_in_test": {
        "title": "Locked in Test",
        "type": "boolean",
        "default": false,
        "icon": "DefaultProperty"
      },
      "runbooks": {
        "title": "Runbooks",
        "type": "array",
        "icon": "Misconfiguration",
        "items": {
          "type": "string",
          "format": "url"
        }
      },
      "monitor_dashboards": {
        "title": "Monitor Dashboards",
        "type": "array",
        "icon": "Grafana",
        "items": {
          "type": "string",
          "format": "url"
        }
      },
      "spec": {
        "title": "Spec",
        "type": "string",
        "description": "Spec in Prod",
        "icon": "Swagger",
        "format": "yaml",
        "spec": "open-api"
      },
      "last_contributer": {
        "icon": "TwoUsers",
        "title": "Last contributor",
        "type": "string",
        "format": "user"
      },
      "url": {
        "title": "URL",
        "format": "url",
        "type": "string",
        "icon": "Link"
      }
    },
    "required": []
  },
  "mirrorProperties": {
    "on_call": {
      "path": "pager_duty_service.oncall"
    },
    "coverage": {
      "path": "sonar_qube_project.coverage"
    },
    "sonar_qube_vulnerabilities": {
      "path": "sonar_qube_project.numberOfVulnerabilities"
    },
    "security_hotspots": {
      "path": "sonar_qube_project.numberOfHotSpots"
    },
    "prod_health": {
      "path": "prod_runtime.healthStatus"
    },
    "synced_in_prod": {
      "path": "prod_runtime.syncStatus"
    },
    "test_health": {
      "path": "test_runtime.healthStatus"
    },
    "synced_in_test": {
      "path": "test_runtime.syncStatus"
    },
    "health_status": {
      "path": "dev_runtime.healthStatus"
    },
    "sync_status": {
      "path": "dev_runtime.syncStatus"
    },
    "status": {
      "path": "pager_duty_service.status"
    }
  },
  "calculationProperties": {
    "freshness": {
      "title": "Freshness",
      "icon": "Clock",
      "calculation": "((now - ((.properties.last_push) | fromdate)) / 86400) | floor",
      "type": "number",
      "colorized": false,
      "colors": {}
    },
    "slack": {
      "title": "Slack",
      "icon": "Slack",
      "calculation": "\"https://slack.com/\" + .identifier",
      "type": "string"
    }
  },
  "aggregationProperties": {},
  "relations": {
    "sonar_qube_project": {
      "title": "SonarQube Project",
      "target": "sonarQubeProject",
      "required": false,
      "many": false
    },
    "prod_runtime": {
      "title": "Prod runtime",
      "description": "The service's prod runtime",
      "target": "running_service",
      "required": false,
      "many": false
    },
    "snyk_project": {
      "title": "Snyk Project",
      "target": "snykProject",
      "required": false,
      "many": false
    },
    "ecr_repo": {
      "title": "ECR Repo",
      "target": "ecrRepository",
      "required": false,
      "many": false
    },
    "githubTeams": {
      "title": "GitHub teams",
      "target": "githubTeam",
      "required": false,
      "many": true
    },
    "test_runtime": {
      "title": "Test runtime",
      "description": "The service's test runtime",
      "target": "running_service",
      "required": false,
      "many": false
    },
    "pager_duty_service": {
      "title": "PagerDuty Service",
      "description": "Corresponding Pagerduty Service",
      "target": "pagerdutyService",
      "required": false,
      "many": false
    },
    "consumes_api": {
      "title": "Consumes API",
      "target": "api",
      "required": false,
      "many": true
    },
    "dora_last_7_days": {
      "title": "DORA last 7 days",
      "target": "doraMetrics",
      "required": false,
      "many": false
    },
    "team": {
      "title": "Team",
      "target": "idp_team",
      "required": false,
      "many": false
    },
    "domain": {
      "title": "Domain",
      "description": "The domain this service belongs to",
      "target": "domain",
      "required": false,
      "many": false
    },
    "provides_api": {
      "title": "Provides API",
      "target": "api",
      "required": false,
      "many": false
    },
    "dev_runtime": {
      "title": "Dev Runtime",
      "target": "running_service",
      "required": false,
      "many": false
    },
    "dora_last_30_days": {
      "title": "DORA last 30 days",
      "target": "doraMetrics",
      "required": false,
      "many": false
    }
  }
}
GitHub Workflowโ
Create the file .github/workflows/open-slack-channel.yaml in the .github/workflows folder of your repository.
We recommend creating a dedicated repository for the workflows that are used by Port actions.
Github Workflow: Open Slack Channel (Click to expand)
name: Open Slack Channel
on:
  workflow_dispatch:
    inputs:
      channel_name:
        description: Name of the public or private channel to create.
        required: true
        type: string
      is_private:
        description: Create a private channel instead of a public one.
        required: false
        type: boolean
      members:
        description: Add members manually to the channel.
        type: array
        required: false
      port_context:
        description: Details of the action and general port_context (blueprint, run ID, entity identifier from Port, etc...).
        required: true
jobs:
  open-slack-channel:
    runs-on: ubuntu-latest
    steps:
      - name: Log Executing Request to Open Channel
        uses: port-labs/port-github-action@v1
        with:
          clientId: ${{ secrets.PORT_CLIENT_ID }}
          clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
          baseUrl: https://api.getport.io
          operation: PATCH_RUN
          runId: ${{ fromJson(github.event.inputs.port_context).runId }}
          logMessage: "About to create a conversation channel in slack..."
      - name: Create Slack Channel
        id: create_channel
        env:
          SLACK_TOKEN: ${{ secrets.BOT_USER_OAUTH_TOKEN }}
        run: |
          response=$(curl -s -X POST "https://slack.com/api/conversations.create" \
            -H "Authorization: Bearer $SLACK_TOKEN" \
            -H "Content-Type: application/json" \
            --data "{\"name\": \"${{ github.event.inputs.channel_name }}\",\"is_private\": ${{ github.event.inputs.is_private }} }")
          echo "API Response: $response"
          if [[ "$(echo $response | jq -r '.ok')" == "true" ]]; then
            channel_id=$(echo $response | jq -r '.channel.id')
            echo "Channel ID: $channel_id"
            echo "CHANNEL_ID=$channel_id" >> $GITHUB_ENV
          else
            echo "Failed to create Slack channel. Channel ID is null."
            error=$(echo $response | jq -r '.error')
            error_message="${error//_/ }"
            echo "Error: $error_message"
            echo "CREATE_CHANNEL_ERROR=$error_message" >> $GITHUB_ENV
            exit 1
          fi
      - name: Log If Create Channel Request Fails
        if: failure()
        uses: port-labs/port-github-action@v1
        with:
          clientId: ${{ secrets.PORT_CLIENT_ID }}
          clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
          baseUrl: https://api.getport.io
          operation: PATCH_RUN
          runId: ${{ fromJson(github.event.inputs.port_context).runId }}
          logMessage: "Failed to create slack channel: ${{env.CREATE_CHANNEL_ERROR}} โ"
      - name: Log If Create Channel Request is Successful
        uses: port-labs/port-github-action@v1
        with:
          clientId: ${{ secrets.PORT_CLIENT_ID }}
          clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
          baseUrl: https://api.getport.io
          operation: PATCH_RUN
          runId: ${{ fromJson(github.event.inputs.port_context).runId }}
          logMessage: "Channel created successfully, channel Id: ${{env.CHANNEL_ID}} โ
"
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Add Members to Slack Channel
        id: add_members
        if: success()
        env:
          SLACK_TOKEN: ${{ secrets.BOT_USER_OAUTH_TOKEN }}
          CHANNEL_ID: ${{env.CHANNEL_ID}}
          CLIENT_ID: ${{ secrets.PORT_CLIENT_ID }}
          CLIENT_SECRET: ${{ secrets.PORT_CLIENT_SECRET }}
          RUN_ID: ${{ fromJson(github.event.inputs.port_context).runId }}
          MEMBER_EMAILS: ${{ toJSON(github.event.inputs.members) }}
        run: |
          cd slack
          chmod +x add-members-to-channel.sh
          bash add-members-to-channel.sh "$SLACK_TOKEN" "$CHANNEL_ID" "$CLIENT_ID" "$CLIENT_SECRET" "$RUN_ID" "$MEMBER_EMAILS"
      - name: Log Successful Action
        if: steps.add_members.outcome == 'failure'
        uses: port-labs/port-github-action@v1
        with:
          clientId: ${{ secrets.PORT_CLIENT_ID }}
          clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
          baseUrl: https://api.getport.io
          operation: PATCH_RUN
          status: "FAILURE"
          runId: ${{ fromJson(github.event.inputs.port_context).runId }}
          logMessage: "Failed to add members to channel โ"
- Create a bash script (add-members-to-channel.sh) in a folder namedslackat the root of your GitHub repository with this content:
Bash Script: Add Members to Channel (Click to expand)
#!/bin/bash
# Assign arguments to variables
SLACK_TOKEN=$1
CHANNEL_ID=$2
clientId=$3
clientSecret=$4
run_id=$5
MEMBER_EMAILS_JSON=$6
# Get the Port access token
PORT_TOKEN_RESPONSE=$(curl -s -X 'POST' \
  'https://api.getport.io/v1/auth/access_token' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d "{
        \"clientId\": \"$clientId\",
        \"clientSecret\": \"$clientSecret\"
      }"
    )
echo $PORT_TOKEN_RESPONSE
PORT_ACCESS_TOKEN=$(echo $PORT_TOKEN_RESPONSE | jq -r '.accessToken')
# Ensure the access token was obtained successfully
if [ -z "$PORT_ACCESS_TOKEN" ] || [ "$PORT_ACCESS_TOKEN" == "null" ]; then
  error_message="Failed to obtain Port access token โ"
  echo $error_message
  report_error "$error_message"
  exit 1
fi
# Function to report error
report_error() {
  local message=$1
  echo $message
  echo "ADD_MEMBER_TO_CHANNEL_ERROR=$message" >> $GITHUB_ENV
  curl -s -X POST "https://api.getport.io/v1/actions/runs/$run_id/logs" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $PORT_ACCESS_TOKEN" \
    -d "{\"message\": \"$message\"}"
}
user_ids=""
# Convert MEMBER_EMAILS_JSON to an array
readarray -t MEMBER_EMAILS < <(echo $MEMBER_EMAILS_JSON | jq -r 'fromjson | .[]')
for email in "${MEMBER_EMAILS[@]}"; do
  user_response=$(curl -s -X GET "https://slack.com/api/users.lookupByEmail?email=$email" \
    -H "Authorization: Bearer $SLACK_TOKEN")
  if [[ "$(echo $user_response | jq -r '.ok')" == "true" ]]; then
    user_id=$(echo $user_response | jq -r '.user.id')
    user_ids+="${user_id},"
  else
    error_message="Failed to retrieve user id for $email: $(echo $user_response | jq -r '.error' | tr '_' ' ') โ ๏ธ"
    report_error "$error_message"
  fi
done
user_ids=${user_ids%,}
if [[ -n "$user_ids" ]]; then
  invite_response=$(curl -s -X POST "https://slack.com/api/conversations.invite" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $SLACK_TOKEN" \
    --data "{\"channel\":\"$CHANNEL_ID\",\"users\":\"$user_ids\"}")
  if [[ "$(echo $invite_response | jq -r '.ok')" == "false" ]]; then
    error_message="Failed to invite users to channel: $(echo $invite_response | jq -r '.error' | tr '_' ' ') โ ๏ธ"
    report_error "$error_message"
  fi
else
  report_error "No user IDs found to invite."
fi
Port Configurationโ
Create a new self service action using the following JSON configuration.
Open Slack Channel (Click to expand)
Make sure to replace <GITHUB_ORG> and <GITHUB_REPO> with your GitHub organization and repository names respectively.
{
  "identifier": "open_slack_channel",
  "title": "Open Slack Channel",
  "icon": "Slack",
  "description": "Create and slack channel and optionally add members to it",
  "trigger": {
    "type": "self-service",
    "operation": "DAY-2",
    "userInputs": {
      "properties": {
        "channel_name": {
          "icon": "Slack",
          "title": "Channel Name",
          "type": "string",
          "default": {
            "jqQuery": "\"incident-\"+.entity.identifier"
          }
        },
        "is_private": {
          "description": "Create a private channel instead of a public one",
          "title": "Is Private",
          "type": "boolean",
          "default": false,
          "icon": "Slack"
        },
        "members": {
          "items": {
            "type": "string",
            "format": "user"
          },
          "title": "Members",
          "icon": "Slack",
          "type": "array",
          "description": "Add members manually to the channel.",
          "default": {
            "jqQuery": ".entity.properties.code_owners"
          }
        }
      },
      "required": [
        "channel_name"
      ],
      "order": [
        "channel_name",
        "members",
        "is_private"
      ]
    },
    "blueprintIdentifier": "service"
  },
  "invocationMethod": {
    "type": "GITHUB",
    "org": "<GITHUB_ORG>",
    "repo": "<GITHUB_REPO>",
    "workflow": "open-slack-channel.yaml",
    "workflowInputs": {
      "channel_name": "{{.inputs.\"channel_name\"}}",
      "is_private": "{{.inputs.\"is_private\"}}",
      "members": "{{.inputs.\"members\"}}",
      "port_context": {
        "entity": "{{.entity}}",
        "blueprint": "{{.action.blueprint}}",
        "runId": "{{.run.id}}",
        "trigger": "{{ .trigger }}"
      }
    },
    "reportWorkflowStatus": true
  },
  "requiredApproval": false
}
Now you should see the Open Slack Channel action in the self-service page. ๐
Let's test it!โ
- Head to the Self Service hub
- Click on the Open Slack Channelaction
- Enter your preferred details for channel_nameand optionally addmembers. You can toggle theis_privateflag to make the channel private.
- Click on Execute
- Done! wait for the channel to be created in slack.