slack-orb: Windows support not working in version 4

Orb version: 4.1.1

What happened:

Based on discussion in https://github.com/CircleCI-Public/slack-orb/issues/145, we upgrade our slack orb usage to version 4.

We have a job that runs on the windows executor:

  <job name>:
    executor:
      name: win/default
      shell: powershell.exe
    steps:
      ...
      - slack/notify:
          channel: <channel id>
          event: fail
          template: basic_fail_1

What we see is:

At line:1 char:18
+ BuildMessageBody() {
+                  ~
An expression was expected after '('.
At line:6 char:7
+     if [ -n "$SLACK_PARAM_CUSTOM" ]; then
+       ~
Missing '(' after 'if' in if statement.
At line:6 char:9
+     if [ -n "$SLACK_PARAM_CUSTOM" ]; then
+         ~
Missing type name after '['.
At line:26 char:13
+ PostToSlack() {
+             ~
An expression was expected after '('.
At line:31 char:8
+     for i in $(eval echo \""$SLACK_PARAM_CHANNEL"\" | sed "s/,/ /g")
+        ~
Missing opening '(' after keyword 'for'.
At line:32 char:7
+     do
+       ~
Missing statement body in do loop.
At line:37 char:11
+         --data \
+           ~
Missing expression after unary operator '--'.
At line:37 char:11
+         --data \
+           ~~~~
Unexpected token 'data' in expression or statement.
At line:37 char:15
+         --data \
+               ~
The Data section is missing its statement block.
At line:38 char:27
+ ...      "$SLACK_MSG_BODY" https://slack.com/api/chat.postMessage | jq '{ ...
+                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unexpected token 'https://slack.com/api/chat.postMessage' in expression or statement.
Not all parse errors were reported.  Correct the reported errors and try again.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ExpectedExpression
 

Exited with code exit status 1

Expected behavior:

For the notification to be sent successfully, like it is on the linux and macOS executors.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (3 by maintainers)

Most upvoted comments

Hey, @tom-james-watson and @Kurt-von-Laven 👋

Support for Windows was implemented in v4.12.0. If you want to give it a shot, make sure to choose bash.exe as your shell in the Windows executor.

Let me know how it goes!

@Kurt-von-Laven You’re right, I don’t know why I thought completely reimplmenting the script in PowerShell was optimal – for some reason, a few of us were under the impression that simply setting bash as the shell would break things, and it’s likely this used to be the case, but it appears that just setting the shell for the steps works fine in #282. Moving forward with this approach.

I would like to challenge the notion that PowerShell support is important. Windows support is important, and the Windows image ships with bash. I believe the simplest solution would be to permit a default shell to be specified consistently on all platforms. The Slack orb is not the only orb that would benefit from this.

In the meantime, here is a better workaround. It turns out the use of artifacts is unnecessary, and it’s risky to assume that the most recent completed job on the same branch is the correct job to report the status of. A better solution is to search for the most recent completed job with the same commit hash using the CircleCI API. This also enables propagation of cancellations to the notify job. Put the following code in .circleci/trickSlackOrb.sh:

#!/bin/bash

set -eufo pipefail

# Issues a v1.1 CircleCI API request to the given relative path within this
# project, and outputs the JSON response to stdout. Specify the HTTP request
# method as the second argument. CIRCLE_TOKEN is not a CircleCI built-in and
# must be provided by a context. It must be a CircleCI API token with access to
# this project and the required scope. The environment variable VCS_TYPE is not
# a CircleCI built-in and should be set from the CircleCI config.yml file to
# << pipeline.project.type >>. See
# https://circleci.com/docs/2.0/pipeline-variables/#pipeline-values.
makeApiRequest() {
  curl \
    --request "$2" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --header "Circle-Token: $CIRCLE_TOKEN" \
    "https://circleci.com/api/v1.1/project/$VCS_TYPE/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/$1"
}

# Output the value of the given JSON key to stdout. The second parameter is the
# JSON string to search.
getJsonValue() {
  local match="$(grep --only-matching "\"$1\"\s*:\s*\"[^\"]*\"" <<< "$2")"
  # Get the value between the third and fourth double quotes.
  cut --delimiter=\" --fields=4 <<< "$match"
}

# Trick the Slack orb into reporting the status of the most recently completed
# job preceding this one that has the same VCS commit hash. Fail this job if the
# preceding one failed. Cancel this job if the preceding one was cancelled.
# Overwrite the CIRCLE_JOB environment variable with the prior job's name and
# the CIRCLE_BUILD_URL environment variable with the prior job's URL. The other
# CIRCLE_* environment variables that Slack reads from should be the same
# between this notify job and the corresponding prior job. If no corresponding
# job can be found, fail this job without tricking Slack.
trickSlackOrb() {
  local buildNum
  for ((buildNum = $CIRCLE_BUILD_NUM - 1; buildNum > 0; buildNum--))
  do
    # This API request requires that CIRCLE_TOKEN have at least the read only
    # scope. See https://circleci.com/docs/api/v1/#single-job.
    local jobMetadata="$(makeApiRequest "$buildNum" "GET")"

    local job="$(getJsonValue "CIRCLE_JOB" "$jobMetadata")"
    if [[ "$job" != "notify" ]] &&
      grep --quiet "\"vcs_revision\":\"$CIRCLE_SHA1\"" <<< "$jobMetadata" &&
      grep --quiet '"lifecycle":"finished"' <<< "$jobMetadata" &&
      grep --quiet '"dont_build":null' <<< "$jobMetadata"
    then
      if grep --quiet '"outcome":"canceled"' <<< "$jobMetadata"
      then
        # Cancels the currently executing CircleCI job, and outputs a JSON document
        # containing metadata regarding this job to stdout. See
        # https://circleci.com/docs/api/v1/#cancel-a-build. This API request
        # requires that CIRCLE_TOKEN token have the admin scope.
        makeApiRequest "$CIRCLE_BUILD_NUM/cancel" "POST"
        # Give the cancellation up to a minute to take effect before failing.
        sleep 60
        break
      fi
      local buildUrl="$(getJsonValue "build_url" "$jobMetadata")"
      echo "export CIRCLE_JOB=$job" >> $BASH_ENV
      echo "export CIRCLE_BUILD_URL=$buildUrl" >> $BASH_ENV
      grep --quiet '"outcome":"success"' <<< "$jobMetadata" && return
      break
    fi
  done
  exit 1
}

trickSlackOrb

Include an extra job in your .circleci/config.yml that runs the script and issues the Slack notification:

version: 2.1
orbs:
  slack: circleci/slack@4.4.2
  windows: circleci/windows@2.4.0
jobs:
  build:
    executor: windows/default
    steps:
...
  notify:
    docker:
      - image: cimg/base:stable
    resource_class: small
    steps:
      - checkout
      - run:
          name: Trick the Slack orb into reporting the status of the most recently finished preceding build job.
          command: source .circleci/trickSlackOrb.sh
          environment:
            VCS_TYPE: << pipeline.project.type >>
      - slack/notify:
          event: fail
          template: basic_fail_1
      - slack/notify:
          event: pass
          template: basic_success_1
workflows:
  build:
    jobs:
      - build
  # Take advantage of the fact that free CircleCI accounts are limited to
  # running one workflow at a time. If you are on a paid account, these
  # workflows will instead run in parallel. Consider submitting a pull request
  # to the Slack orb to use the bash.exe shell on Windows, using
  # https://github.com/eddiewebb/circleci-queue, or using the CircleCI API to
  # wait for the build workflow to complete.
  notify:
    jobs:
      - notify:
          context:
            # a context that defines the CIRCLE_TOKEN environment variable
            # to be a CircleCI API token for your project with Admin scope
            - circleci-api-admin
            # a context that defines the SLACK_ACCESS_TOKEN and SLACK_DEFAULT_CHANNEL
            # environment variables as specified by
            # https://github.com/CircleCI-Public/slack-orb#readme
            - slack

For future reference, version 4 of the slack orb does not work in Windows. This is also mentioned with more context in the wiki’s FAQ section.

It mostly works out of the box - we’ve noticed a minor issue with our sed syntax when trying to escape templates for execution, and trying to get to the bottom of it. For the most part, though, it does just work, thankfully.

Yeah, I believe it’s possible to specify shell: bash.exe for individual jobs, so that’s what I had been expecting would be the case for windows support. If the plan is to eventually support this then I would leave this open as a feature request so people can track it.