Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions core/src/shared/issue-ref.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
// front makes it part of an identifier, a version, a hex colour or a URL fragment (`C#7`, `1.2#3`,
// `#3366ff`, `help/#123`), and a word character behind means the number keeps going (`#1360abc`).
// `owner/repo#12` is its own shape, tried separately, so this separation cannot swallow it: there
// the `#` follows a repo name rather than a space.
const ISSUE_REF = /(?<![\w./-])#(\d{1,7})(?![\w])|(?:github\.com\/)?([\w.-]+)\/([\w.-]+)#(\d{1,7})(?![\w])|github\.com\/([\w.-]+)\/([\w.-]+)\/(?:issues|pull)\/(\d{1,7})(?![\w])/gi
// the `#` follows a repo name rather than a space. It needs the same boundary in front, or a URL
// whose path has a segment before the `#` reads as that shape and names an issue nobody meant
// (`https://example.com/page#123`, #1392).
const ISSUE_REF = /(?<![\w./-])#(\d{1,7})(?![\w])|(?<![\w./-])(?:github\.com\/)?([\w.-]+)\/([\w.-]+)#(\d{1,7})(?![\w])|github\.com\/([\w.-]+)\/([\w.-]+)\/(?:issues|pull)\/(\d{1,7})(?![\w])/gi

// The id a match of `ISSUE_REF` names, normalised to `#1234`. The three shapes carry their number in
// different groups (1, 4, 7); every reader takes it from here, so no caller can pick the wrong one.
Expand Down
29 changes: 29 additions & 0 deletions core/test/issue-ref-url-fragment.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// A URL fragment is not an issue reference (#1392). The repository-qualified shape
// `owner/repo#12` has no lookbehind, so a link whose path carries a segment before the `#` read as
// `<host>/<segment>#12` — `https://example.com/page#123` named issue #123 — and the dispatch wrote
// a card for an issue nobody meant (#1360).
import assert from 'node:assert/strict'
import { test } from 'node:test'
import { issueRefs, namesIssue } from '../src/shared/issue-ref.js'

const fragments = [
'see https://example.com/page#123 for details',
'https://example.com/docs/guide#12',
'read https://docs.example.org/a/b#42 then',
]

for (const text of fragments) {
test(`a URL fragment is not an issue reference: ${text}`, () => {
assert.deepEqual(issueRefs(text), [], text)
})
}

test('the shapes that name an issue keep working beside a URL', () => {
assert.deepEqual(issueRefs('owner/repo#1360'), ['#1360'])
assert.deepEqual(issueRefs('see owner/repo#1360 for the fix'), ['#1360'])
assert.deepEqual(issueRefs('please rebase #1360 onto main'), ['#1360'])
assert.deepEqual(issueRefs('https://github.com/o/r/issues/1360'), ['#1360'])
assert.deepEqual(issueRefs('@Dev-2 rebase owner/repo#1360'), ['#1360'])
assert.equal(namesIssue('https://example.com/docs/guide#12', 12), false)
assert.equal(namesIssue('owner/repo#1360', 1360), true)
})
6 changes: 4 additions & 2 deletions patches/ds-bot/files/src/shared/issue-ref.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
// front makes it part of an identifier, a version, a hex colour or a URL fragment (`C#7`, `1.2#3`,
// `#3366ff`, `help/#123`), and a word character behind means the number keeps going (`#1360abc`).
// `owner/repo#12` is its own shape, tried separately, so this separation cannot swallow it: there
// the `#` follows a repo name rather than a space.
const ISSUE_REF = /(?<![\w./-])#(\d{1,7})(?![\w])|(?:github\.com\/)?([\w.-]+)\/([\w.-]+)#(\d{1,7})(?![\w])|github\.com\/([\w.-]+)\/([\w.-]+)\/(?:issues|pull)\/(\d{1,7})(?![\w])/gi
// the `#` follows a repo name rather than a space. It needs the same boundary in front, or a URL
// whose path has a segment before the `#` reads as that shape and names an issue nobody meant
// (`https://example.com/page#123`, #1392).
const ISSUE_REF = /(?<![\w./-])#(\d{1,7})(?![\w])|(?<![\w./-])(?:github\.com\/)?([\w.-]+)\/([\w.-]+)#(\d{1,7})(?![\w])|github\.com\/([\w.-]+)\/([\w.-]+)\/(?:issues|pull)\/(\d{1,7})(?![\w])/gi

// The id a match of `ISSUE_REF` names, normalised to `#1234`. The three shapes carry their number in
// different groups (1, 4, 7); every reader takes it from here, so no caller can pick the wrong one.
Expand Down
29 changes: 29 additions & 0 deletions patches/ds-bot/files/test/issue-ref-url-fragment.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// A URL fragment is not an issue reference (#1392). The repository-qualified shape
// `owner/repo#12` has no lookbehind, so a link whose path carries a segment before the `#` read as
// `<host>/<segment>#12` — `https://example.com/page#123` named issue #123 — and the dispatch wrote
// a card for an issue nobody meant (#1360).
import assert from 'node:assert/strict'
import { test } from 'node:test'
import { issueRefs, namesIssue } from '../src/shared/issue-ref.js'

const fragments = [
'see https://example.com/page#123 for details',
'https://example.com/docs/guide#12',
'read https://docs.example.org/a/b#42 then',
]

for (const text of fragments) {
test(`a URL fragment is not an issue reference: ${text}`, () => {
assert.deepEqual(issueRefs(text), [], text)
})
}

test('the shapes that name an issue keep working beside a URL', () => {
assert.deepEqual(issueRefs('owner/repo#1360'), ['#1360'])
assert.deepEqual(issueRefs('see owner/repo#1360 for the fix'), ['#1360'])
assert.deepEqual(issueRefs('please rebase #1360 onto main'), ['#1360'])
assert.deepEqual(issueRefs('https://github.com/o/r/issues/1360'), ['#1360'])
assert.deepEqual(issueRefs('@Dev-2 rebase owner/repo#1360'), ['#1360'])
assert.equal(namesIssue('https://example.com/docs/guide#12', 12), false)
assert.equal(namesIssue('owner/repo#1360', 1360), true)
})
Loading