Skip to content

Slack notification service links incorrectly formatted when the link text contains square brackets

Summary

GitLab CI job names can contain pairs of square brackets ([ ]) thanks to the parallel:matrix feature. When link text contains a pair of square brackets, the links are not formatted correctly by the Slack notification service.

Screen_Shot_2021-11-10_at_7.23.12_AM

Steps to reproduce

  1. Apply this patch (git apply patch-file)

    diff --git a/spec/models/integrations/chat_message/pipeline_message_spec.rb b/spec/models/integrations/chat_message/pipeline_message_spec.rb
    index a80d13d7f5d..fa3be2b29c9 100644
    --- a/spec/models/integrations/chat_message/pipeline_message_spec.rb
    +++ b/spec/models/integrations/chat_message/pipeline_message_spec.rb
    @@ -332,6 +332,22 @@
        end
      end
    
    +  context "when name contains brackets" do
    +    before do
    +      args[:builds] = [
    +        { id: 1, name: "test: [arg1, arg2]", status: "failed", stage: "test" }
    +      ]
    +    end
    +
    +    it "correctly formats links" do
    +      expect(subject.attachments.first[:fields][3]).to eq(
    +        title: "Failed jobs",
    +        value: "<http://example.gitlab.com/-/jobs/1|test: [arg1, arg2]>",
    +        short: true
    +      )
    +    end
    +  end
    +
      context "when the CI config file contains a YAML error" do
        let(:has_yaml_errors) { true }
  2. Run bundle exec rspec spec/models/integrations/chat_message/pipeline_message_spec.rb

  3. Tests fail when they should pass

    Failures:
    
      1) Integrations::ChatMessage::PipelineMessage when name contains brackets correctly formats links
        Failure/Error:
          expect(subject.attachments.first[:fields][3]).to eq(
            title: "Failed jobs",
            value: "<http://example.gitlab.com/-/jobs/1|test: [arg1, arg2]>",
            short: true
          )
        
          expected: {:short=>true, :title=>"Failed jobs", :value=>"<http://example.gitlab.com/-/jobs/1|test: [arg1, arg2]>"}
                got: {:short=>true, :title=>"Failed job", :value=>"[test: [arg1, arg2]](http://example.gitlab.com/-/jobs/1)"}
        
          (compared using ==)
        
          Diff:
          @@ -1,4 +1,4 @@
            :short => true,
          -:title => "Failed jobs",
          -:value => "<http://example.gitlab.com/-/jobs/1|test: [arg1, arg2]>",
          +:title => "Failed job",
          +:value => "[test: [arg1, arg2]](http://example.gitlab.com/-/jobs/1)",
          
        # ./spec/models/integrations/chat_message/pipeline_message_spec.rb:343:in `block (3 levels) in <top (required)>'
        # ./spec/spec_helper.rb:406:in `block (3 levels) in <top (required)>'
        # ./spec/support/sidekiq_middleware.rb:9:in `with_sidekiq_server_middleware'
        # ./spec/spec_helper.rb:397:in `block (2 levels) in <top (required)>'
        # ./spec/spec_helper.rb:393:in `block (3 levels) in <top (required)>'
        # ./lib/gitlab/application_context.rb:31:in `with_raw_context'
        # ./spec/spec_helper.rb:393:in `block (2 levels) in <top (required)>'
        # ./spec/support/database/query_analyzer.rb:9:in `block (3 levels) in <main>'
        # ./lib/gitlab/database/query_analyzer.rb:42:in `within'
        # ./spec/support/database/query_analyzer.rb:9:in `block (2 levels) in <main>'
        # ./spec/support/database/prevent_cross_joins.rb:102:in `block (3 levels) in <main>'
        # ./spec/support/database/prevent_cross_joins.rb:56:in `with_cross_joins_prevented'
        # ./spec/support/database/prevent_cross_joins.rb:102:in `block (2 levels) in <main>'
    
    Finished in 3 minutes 9.7 seconds (files took 1 minute 27.35 seconds to load)
    38 examples, 1 failure
    
    Failed examples:
    
    rspec ./spec/models/integrations/chat_message/pipeline_message_spec.rb:342 # Integrations::ChatMessage::PipelineMessage when name contains brackets correctly formats links

Branch example: https://gitlab.com/gitlab-org/gitlab/-/commits/bwill/slack-brackets-links-example

What is the current bug behavior?

The links are presented in markdown format [text](link)

What is the expected correct behavior?

The links should be presented in Slack link format <link|text>

Possible fixes

We use ::Slack::Messenger::Util::LinkFormatter in order to format these links. In many places in the codebase, we have a link_text and a link which we format into a markdown string like [link_text](link) and then pass it to LinkFormatter#format. This seems very inefficient, since LinkFormatter#format needs to parse out the link_text and link using regex. Instead, we should probable make LinkFormatter#slack_link public, and give it the link_text and link.

Edited by Thiago Figueiró