diff --git a/scripts/commands/db/update.ts b/scripts/commands/db/update.ts index 943e512872..0513cf62e4 100644 --- a/scripts/commands/db/update.ts +++ b/scripts/commands/db/update.ts @@ -507,6 +507,21 @@ async function removeFeed(issue: Issue) { return } + if (foundFeed.is_main) { + const nextFeed = data.feeds.first( + (feed: Feed) => feed.channel === channelId && feed.id !== feedId + ) + if (!nextFeed) { + log.error( + `The feed with ID "${feedId}" is the only feed for the "${channelId}" channel and therefore cannot be deleted` + ) + skippedIssues.add(issue) + return + } + nextFeed.is_main = true + onFeedNewMain(channelId, nextFeed.id, log) + } + data.feeds.remove((feed: Feed) => feed.getStreamId() === foundFeed.getStreamId()) data.feedsKeyByStreamId.remove(foundFeed.getStreamId()) diff --git a/scripts/commands/issue/validate.ts b/scripts/commands/issue/validate.ts index c05fc3d194..36b9668343 100644 --- a/scripts/commands/issue/validate.ts +++ b/scripts/commands/issue/validate.ts @@ -145,12 +145,24 @@ function validateAddCityRequest(dataSet: DataSet) { if (!cityCode) { errors.push('The request is missing the "City Code"') done() + } else { + const isDuplicate = data.citiesKeyByCode.has(cityCode) + if (isDuplicate) { + errors.push(`The database already contains a city with code "${cityCode}"`) + done() + } } const wikidataId = dataSet.getString('wikidata_id')?.trim() if (!wikidataId) { errors.push('The request is missing the "Wikidata ID"') done() + } else { + const isDuplicate = data.citiesKeyByWikidataId.has(wikidataId) + if (isDuplicate) { + errors.push(`The database already contains a city with wikidata_id "${wikidataId}"`) + done() + } } validateCityData(dataSet) @@ -326,6 +338,15 @@ function validateAddLogoRequest(dataSet: DataSet) { if (!logoUrl) { errors.push('The request is missing the "Logo URL"') done() + } else { + const foundLogos = data.logosGroupedByUrl.get(logoUrl) || [] + const duplicate = foundLogos.find(logo => logo.channel === channelId) + if (duplicate) { + errors.push( + `The database already contains a logo with url "${logoUrl}" and the channel "${channelId}"` + ) + done() + } } validateLogoData(dataSet) diff --git a/scripts/core/dataSet.ts b/scripts/core/dataSet.ts index e7cf3116cb..23314a6632 100644 --- a/scripts/core/dataSet.ts +++ b/scripts/core/dataSet.ts @@ -80,29 +80,29 @@ export class DataSet { } getBoolean(key: string): boolean | undefined { + if (this.isDeleted(key)) return undefined + if (this.missing(key)) return undefined return this.#data.get(key) === 'TRUE' ? true : false } getString(key: string): string | undefined { - const deleteSymbol = '~' + if (this.isDeleted(key)) return undefined - return this.missing(key) - ? undefined - : this.#data.get(key) === deleteSymbol - ? '' - : String(this.#data.get(key)) + return this.missing(key) ? undefined : String(this.#data.get(key)) } getNumber(key: string): number | undefined { + if (this.isDeleted(key)) return undefined + const string = this.getString(key) return string ? Number(string) : undefined } getArray(key: string): string[] | undefined { - const deleteSymbol = '~' + if (this.isDeleted(key)) return undefined if (this.#data.missing(key)) return undefined @@ -110,7 +110,7 @@ export class DataSet { if (typeof value !== 'string') return undefined - return value === deleteSymbol ? [] : value.split(/[\r\n;]/) + return value.split(/[\r\n;]/) } getChanged(): string[] { diff --git a/scripts/core/db.ts b/scripts/core/db.ts index 9a6f268ba2..8e8eb3ff18 100644 --- a/scripts/core/db.ts +++ b/scripts/core/db.ts @@ -34,6 +34,7 @@ let data: DatabaseData = { logos: new Collection(), citiesKeyByCode: new Dictionary(), + citiesKeyByWikidataId: new Dictionary(), feedsGroupedByChannelId: new Dictionary(), feedsKeyByStreamId: new Dictionary(), channelsKeyById: new Dictionary(), @@ -62,6 +63,7 @@ let cache: DatabaseData = { logos: new Collection(), citiesKeyByCode: new Dictionary(), + citiesKeyByWikidataId: new Dictionary(), feedsGroupedByChannelId: new Dictionary(), feedsKeyByStreamId: new Dictionary(), channelsKeyById: new Dictionary(), @@ -174,6 +176,7 @@ async function loadData(): Promise { (subdivision: Subdivision) => subdivision.code ) data.citiesKeyByCode = data.cities.keyBy((city: City) => city.code) + data.citiesKeyByWikidataId = data.cities.keyBy((city: City) => city.wikidata_id) const locations: Collection = new Collection() data.cities.forEach(city => { @@ -212,6 +215,7 @@ function cacheData() { countries: data.countries.clone(), logos: data.logos.clone(), citiesKeyByCode: data.citiesKeyByCode.clone(), + citiesKeyByWikidataId: data.citiesKeyByWikidataId.clone(), feedsGroupedByChannelId: data.feedsGroupedByChannelId.clone(), feedsKeyByStreamId: data.feedsKeyByStreamId.clone(), channelsKeyById: data.channelsKeyById.clone(), @@ -241,6 +245,7 @@ function resetData() { countries: cache.countries, logos: cache.logos, citiesKeyByCode: cache.citiesKeyByCode, + citiesKeyByWikidataId: cache.citiesKeyByWikidataId, feedsGroupedByChannelId: cache.feedsGroupedByChannelId, feedsKeyByStreamId: cache.feedsKeyByStreamId, channelsKeyById: cache.channelsKeyById, diff --git a/scripts/models/channel.ts b/scripts/models/channel.ts index 654bbc7c40..4fb3a0348b 100644 --- a/scripts/models/channel.ts +++ b/scripts/models/channel.ts @@ -46,16 +46,16 @@ export class Channel extends sdk.Models.Channel implements Validator { update(dataSet: DataSet): this { const data = { channel_name: dataSet.getString('channel_name'), - alt_names: dataSet.getArray('alt_names'), - network: dataSet.getString('network'), - owners: dataSet.getArray('owners'), + alt_names: dataSet.isDeleted('alt_names') ? [] : dataSet.getArray('alt_names'), + network: dataSet.isDeleted('network') ? null : dataSet.getString('network'), + owners: dataSet.isDeleted('owners') ? [] : dataSet.getArray('owners'), country: dataSet.getString('country'), - categories: dataSet.getArray('categories'), + categories: dataSet.isDeleted('categories') ? [] : dataSet.getArray('categories'), is_nsfw: dataSet.getBoolean('is_nsfw'), - launched: dataSet.getString('launched'), - closed: dataSet.getString('closed'), - replaced_by: dataSet.getString('replaced_by'), - website: dataSet.getString('website') + launched: dataSet.isDeleted('launched') ? null : dataSet.getString('launched'), + closed: dataSet.isDeleted('closed') ? null : dataSet.getString('closed'), + replaced_by: dataSet.isDeleted('replaced_by') ? null : dataSet.getString('replaced_by'), + website: dataSet.isDeleted('website') ? null : dataSet.getString('website') } if (data.channel_name !== undefined) this.name = data.channel_name diff --git a/scripts/models/feed.ts b/scripts/models/feed.ts index 702d346817..d6bd808f4d 100644 --- a/scripts/models/feed.ts +++ b/scripts/models/feed.ts @@ -48,7 +48,7 @@ export class Feed extends sdk.Models.Feed implements Validator { update(dataSet: DataSet): this { const data = { feed_name: dataSet.getString('feed_name'), - alt_names: dataSet.getArray('alt_names'), + alt_names: dataSet.isDeleted('alt_names') ? [] : dataSet.getArray('alt_names'), is_main: dataSet.getBoolean('is_main'), broadcast_area: dataSet.getArray('broadcast_area'), timezones: dataSet.getArray('timezones'), diff --git a/scripts/models/logo.ts b/scripts/models/logo.ts index 676270bfbe..aad95fbe6e 100644 --- a/scripts/models/logo.ts +++ b/scripts/models/logo.ts @@ -34,9 +34,9 @@ export class Logo extends sdk.Models.Logo implements Validator { update(dataSet: DataSet): this { const data = { channel: dataSet.getString('new_channel_id'), - feed: dataSet.getString('new_feed_id'), + feed: dataSet.isDeleted('new_feed_id') ? null : dataSet.getString('new_feed_id'), in_use: dataSet.getBoolean('in_use'), - tags: dataSet.getArray('tags'), + tags: dataSet.isDeleted('tags') ? [] : dataSet.getArray('tags'), width: dataSet.getNumber('width'), height: dataSet.getNumber('height'), format: dataSet.getString('format') diff --git a/scripts/types/db.d.ts b/scripts/types/db.d.ts index 230055ced8..d2d8970c93 100644 --- a/scripts/types/db.d.ts +++ b/scripts/types/db.d.ts @@ -32,6 +32,7 @@ export type DatabaseData = { regions: Collection subdivisions: Collection cities: Collection + citiesKeyByWikidataId: Dictionary citiesKeyByCode: Dictionary channelsKeyById: Dictionary countriesKeyByCode: Dictionary diff --git a/tests/__data__/expected/db/update/data/feeds.csv b/tests/__data__/expected/db/update/data/feeds.csv index 98dc618fa7..c5dba96c91 100644 --- a/tests/__data__/expected/db/update/data/feeds.csv +++ b/tests/__data__/expected/db/update/data/feeds.csv @@ -1,4 +1,5 @@ channel,id,name,alt_names,is_main,broadcast_area,timezones,languages,format +01TV.fr,HD,HD,,TRUE,c/FR,Europe/Paris,fra,576i 0TV.dk,SD,SD,,TRUE,c/DK,Europe/Copenhagen,dan,576i 1000xHoraTV.uy,HD,HD,Oeste;Este,TRUE,c/CN,Africa/Johannesburg;Africa/Kigali,zho,576i 1000xHoraTV.uy,SD,SD,,FALSE,c/UY,America/Montevideo,spa,576i diff --git a/tests/__data__/expected/db/update/data/logos.csv b/tests/__data__/expected/db/update/data/logos.csv index b549bfe5e6..26b5229d23 100644 --- a/tests/__data__/expected/db/update/data/logos.csv +++ b/tests/__data__/expected/db/update/data/logos.csv @@ -13,6 +13,7 @@ M5.hu,HD,TRUE,,512,512,PNG,https://i.imgur.com/y21wFd0.png WenzhouEconomicandEducation.cn,,TRUE,,80,80,JPEG,https://www.tvchinese.net/uploads/tv/wzjjkj.jpg YiwuBusinessChannel.cn,,TRUE,horizontal;color,80,80,JPEG,https://www.tvchinese.net/uploads/tv/yiwutv.jpg YiwuNewsIntegratedChannel.cn,,FALSE,horizontal,80,80,JPEG,https://www.tvchinese.net/uploads/tv/yiwutv.jpg -ZonaDAZN3.it,HD,TRUE,,400,400,PNG,https://i.imgur.com/Jop3Vip.png +ZonaDAZN3.it,,TRUE,,400,400,PNG,https://i.imgur.com/Jop3Vip.png +ZonaDAZN3.it,,TRUE,,400,400,PNG,https://i.imgur.com/Jop3Vip.png ZTVWorld.hu,,TRUE,,0,0,PNG,https://i.imgur.com/wPqCtwR.png ZutTV.ve,HD,TRUE,,0,0,PNG,https://i.imgur.com/wPqCtwK.png \ No newline at end of file diff --git a/tests/__data__/expected/issue/validate/logs/cities_add_duplicate.txt b/tests/__data__/expected/issue/validate/logs/cities_add_duplicate.txt new file mode 100644 index 0000000000..7e36db63c1 --- /dev/null +++ b/tests/__data__/expected/issue/validate/logs/cities_add_duplicate.txt @@ -0,0 +1,2 @@ +The request contains error(s): +- The database already contains a city with wikidata_id "Q386802" \ No newline at end of file diff --git a/tests/__data__/expected/issue/validate/logs/logos_add_duplicate.txt b/tests/__data__/expected/issue/validate/logs/logos_add_duplicate.txt new file mode 100644 index 0000000000..59600be905 --- /dev/null +++ b/tests/__data__/expected/issue/validate/logs/logos_add_duplicate.txt @@ -0,0 +1,2 @@ +The request contains error(s): +- The database already contains a logo with url "https://i.imgur.com/7oNe8xj.png" and the channel "SagarmathaTV.np" \ No newline at end of file diff --git a/tests/__data__/input/db/update/data/feeds.csv b/tests/__data__/input/db/update/data/feeds.csv index 8834375ac0..19c1f82cf3 100644 --- a/tests/__data__/input/db/update/data/feeds.csv +++ b/tests/__data__/input/db/update/data/feeds.csv @@ -1,6 +1,7 @@ channel,id,name,alt_names,is_main,broadcast_area,timezones,languages,format 002RadioTV.do,SD,SD,,TRUE,c/DO,America/Santo_Domingo,spa,480i 01TV.fr,SD,SD,,TRUE,c/FR,Europe/Paris,fra,576i +01TV.fr,HD,HD,,FALSE,c/FR,Europe/Paris,fra,576i 0TV.dk,SD,SD,,TRUE,c/DK,Europe/Copenhagen,dan,576i 1000xHoraTV.uy,SD,SD,,TRUE,c/UY,America/Montevideo,spa,576i 24HorasInternacional.es,SD,SD,,TRUE,c/ES,Europe/Madrid,spa,576i @@ -13,7 +14,7 @@ ZonaDAZN3.it,SD,SD,,FALSE,c/IT,Europe/Rome,ita,576i BeijingSatelliteTV.cn,SD,SD,,TRUE,c/DO,America/Santo_Domingo,spa,480i M5.hu,SD,SD,Sud,FALSE,c/DO,America/Santo_Domingo,spa,480i M5.hu,West,West,,TRUE,c/DO,America/Santo_Domingo,spa,480i -Channel82.bm,SD,SD,,FALSE,c/BM,America/Santo_Domingo,eng,480i +Channel82.bm,SD,SD,ch82,FALSE,c/BM,America/Santo_Domingo,eng,480i TrueCrime.uk,SD,SD,,TRUE,c/UK;c/IE,Europe/London,eng,576i ZutTV.ve,SD,SD,,TRUE,c/UK;c/IE;ct/ALMIL,Europe/London,eng,576i ZTVWorld.hu,SD,SD,,TRUE,c/HU,Europe/London,eng,576i diff --git a/tests/__data__/input/db/update/data/logos.csv b/tests/__data__/input/db/update/data/logos.csv index 5852adcf69..46cdcedd1a 100644 --- a/tests/__data__/input/db/update/data/logos.csv +++ b/tests/__data__/input/db/update/data/logos.csv @@ -8,7 +8,7 @@ BeijingSatelliteTV.cn,,TRUE,,512,512,PNG,https://i.imgur.com/vsktAez.png M5.hu,SD,TRUE,,512,512,PNG,https://i.imgur.com/y21wFd0.png ZonaDAZN2.it,SD,TRUE,,512,512,PNG,https://i.imgur.com/vMdyLVv.png ZonaDAZN3.it,SD,TRUE,,512,512,PNG,https://i.imgur.com/Jop3Vip.png -ZonaDAZN3.it,HD,TRUE,,512,512,PNG,https://i.imgur.com/Jop3Vip.png +ZonaDAZN3.it,HD,TRUE,test,512,512,PNG,https://i.imgur.com/Jop3Vip.png K04GWD1.us,,TRUE,,0,0,PNG,https://upload.wikimedia.org/wikipedia/en/thumb/3/33/PBS_logo.svg/512px-PBS_logo.svg.png K04JRD1.us,,TRUE,,0,0,PNG,https://upload.wikimedia.org/wikipedia/en/thumb/3/33/PBS_logo.svg/512px-PBS_logo.svg.png K05FWD1.us,,TRUE,,0,0,PNG,https://upload.wikimedia.org/wikipedia/en/thumb/3/33/PBS_logo.svg/512px-PBS_logo.svg.png diff --git a/tests/__data__/input/db/update/issues.js b/tests/__data__/input/db/update/issues.js index e0c5c4d37a..5bd7d5ca7e 100644 --- a/tests/__data__/input/db/update/issues.js +++ b/tests/__data__/input/db/update/issues.js @@ -1091,7 +1091,7 @@ module.exports = [ type: null, active_lock_reason: null, sub_issues_summary: { total: 0, completed: 0, percent_completed: 0 }, - body: '### Channel ID (required)\n\nChannel82.bm\n\n### Feed ID (required)\n\nSD\n\n### Feed Name\n\n_No response_\n\n### Main Feed\n\nNone\n\n### Broadcast Area\n\n_No response_\n\n### Timezones\n\nAtlantic/Bermuda\n\n### Languages\n\n_No response_\n\n### Format\n\nNone\n\n### Notes\n\n_No response_', + body: '### Channel ID (required)\n\nChannel82.bm\n\n### Feed ID (required)\n\nSD\n\n### Alternative Names\n\n~\n\n### Feed Name\n\n_No response_\n\n### Main Feed\n\nNone\n\n### Broadcast Area\n\n_No response_\n\n### Timezones\n\nAtlantic/Bermuda\n\n### Languages\n\n_No response_\n\n### Format\n\nNone\n\n### Notes\n\n_No response_', closed_by: null, reactions: { url: 'https://api.github.com/repos/iptv-org/database/issues/17612/reactions', @@ -1408,7 +1408,7 @@ module.exports = [ closed_at: null, author_association: 'CONTRIBUTOR', active_lock_reason: null, - body: '### Logo URL (required)\n\nhttps://i.imgur.com/Jop3Vip.png\n\n### Tags\n\n_No response_\n\n### Width\n\n400\n\n### Height\n\n400\n\n### Format\n\nPNG\n\n### Notes\n\n_No response_', + body: '### Logo URL (required)\n\nhttps://i.imgur.com/Jop3Vip.png\n\n### New Feed ID\n\n~\n\n### Tags\n\n~\n\n### Width\n\n400\n\n### Height\n\n400\n\n### Format\n\nPNG\n\n### Notes\n\n_No response_', reactions: { url: 'https://api.github.com/repos/iptv-org/database/issues/9903/reactions', total_count: 0, diff --git a/tests/__data__/input/data/blocklist.csv b/tests/__data__/input/issue/validate/data/blocklist.csv similarity index 100% rename from tests/__data__/input/data/blocklist.csv rename to tests/__data__/input/issue/validate/data/blocklist.csv diff --git a/tests/__data__/input/data/categories.csv b/tests/__data__/input/issue/validate/data/categories.csv similarity index 100% rename from tests/__data__/input/data/categories.csv rename to tests/__data__/input/issue/validate/data/categories.csv diff --git a/tests/__data__/input/data/channels.csv b/tests/__data__/input/issue/validate/data/channels.csv similarity index 100% rename from tests/__data__/input/data/channels.csv rename to tests/__data__/input/issue/validate/data/channels.csv diff --git a/tests/__data__/input/data/cities.csv b/tests/__data__/input/issue/validate/data/cities.csv similarity index 100% rename from tests/__data__/input/data/cities.csv rename to tests/__data__/input/issue/validate/data/cities.csv diff --git a/tests/__data__/input/data/countries.csv b/tests/__data__/input/issue/validate/data/countries.csv similarity index 100% rename from tests/__data__/input/data/countries.csv rename to tests/__data__/input/issue/validate/data/countries.csv diff --git a/tests/__data__/input/data/feeds.csv b/tests/__data__/input/issue/validate/data/feeds.csv similarity index 100% rename from tests/__data__/input/data/feeds.csv rename to tests/__data__/input/issue/validate/data/feeds.csv diff --git a/tests/__data__/input/data/languages.csv b/tests/__data__/input/issue/validate/data/languages.csv similarity index 100% rename from tests/__data__/input/data/languages.csv rename to tests/__data__/input/issue/validate/data/languages.csv diff --git a/tests/__data__/input/data/logos.csv b/tests/__data__/input/issue/validate/data/logos.csv similarity index 63% rename from tests/__data__/input/data/logos.csv rename to tests/__data__/input/issue/validate/data/logos.csv index d471b06087..d2c32965e2 100644 --- a/tests/__data__/input/data/logos.csv +++ b/tests/__data__/input/issue/validate/data/logos.csv @@ -1,3 +1,3 @@ channel,feed,in_use,tags,width,height,format,url OmkarTV.np,HD,TRUE,,334,210,PNG,https://i.imgur.com/7oNe8xj.png -SagarmathaTV.np,SD,TRUE,,334,210,PNG,https://i.imgur.com/7oNe8xj.png \ No newline at end of file +SagarmathaTV.np,HD,TRUE,,334,210,PNG,https://i.imgur.com/7oNe8xj.png \ No newline at end of file diff --git a/tests/__data__/input/issues.js b/tests/__data__/input/issue/validate/issues.js similarity index 95% rename from tests/__data__/input/issues.js rename to tests/__data__/input/issue/validate/issues.js index af4293369b..b60cc58c01 100644 --- a/tests/__data__/input/issues.js +++ b/tests/__data__/input/issue/validate/issues.js @@ -1524,7 +1524,7 @@ module.exports = [ blocking: 0, total_blocking: 0 }, - body: '### Channel ID\n\nOmkarTV.np\n\n### Feed ID (optional)\n\nHD\n\n### Logo URL\n\nhttps://i.imgur.com/HR4FCLt.png\n\n### In Use\n\nTRUE\n\n### Tags (optional)\n\n_No response_\n\n### Notes (optional)\n\n_No response_', + body: '### Channel ID\n\nSagarmathaTV.np\n\n### Feed ID (optional)\n\nHD\n\n### Logo URL\n\n https://i.imgur.com/7oNe8xj.png\n\n### In Use\n\nTRUE\n\n### Tags (optional)\n\n_No response_\n\n### Notes (optional)\n\n_No response_', closed_by: null, reactions: { url: 'https://api.github.com/repos/iptv-org/database/issues/31772/reactions', @@ -3444,5 +3444,96 @@ module.exports = [ performed_via_github_app: null, state_reason: null, pinned_comment: null + }, + { + url: 'https://api.github.com/repos/iptv-org/database/issues/31989', + repository_url: 'https://api.github.com/repos/iptv-org/database', + labels_url: 'https://api.github.com/repos/iptv-org/database/issues/31989/labels{/name}', + comments_url: 'https://api.github.com/repos/iptv-org/database/issues/31989/comments', + events_url: 'https://api.github.com/repos/iptv-org/database/issues/31989/events', + html_url: 'https://github.com/iptv-org/database/issues/31989', + id: 5169121848, + node_id: 'I_kwDOG1Kwp88AAAABNBqKOA', + number: 31989, + title: 'Add: Boston', + user: { + login: 'cancerbikash-oss', + id: 268401535, + node_id: 'U_kgDOD_97fw', + avatar_url: 'https://avatars.githubusercontent.com/u/268401535?v=4', + gravatar_id: '', + url: 'https://api.github.com/users/cancerbikash-oss', + html_url: 'https://github.com/cancerbikash-oss', + followers_url: 'https://api.github.com/users/cancerbikash-oss/followers', + following_url: 'https://api.github.com/users/cancerbikash-oss/following{/other_user}', + gists_url: 'https://api.github.com/users/cancerbikash-oss/gists{/gist_id}', + starred_url: 'https://api.github.com/users/cancerbikash-oss/starred{/owner}{/repo}', + subscriptions_url: 'https://api.github.com/users/cancerbikash-oss/subscriptions', + organizations_url: 'https://api.github.com/users/cancerbikash-oss/orgs', + repos_url: 'https://api.github.com/users/cancerbikash-oss/repos', + events_url: 'https://api.github.com/users/cancerbikash-oss/events{/privacy}', + received_events_url: 'https://api.github.com/users/cancerbikash-oss/received_events', + type: 'User', + user_view_type: 'public', + site_admin: false + }, + labels: [ + { + id: 5366738347, + node_id: 'LA_kwDOG1Kwp88AAAABP-Htqw', + url: 'https://api.github.com/repos/iptv-org/database/labels/approved', + name: 'approved', + color: '85DDDE', + default: false, + description: '' + }, + { + id: 8870945667, + node_id: 'LA_kwDOG1Kwp88AAAACEL_jgw', + url: 'https://api.github.com/repos/iptv-org/database/labels/cities:add', + name: 'cities:add', + color: '497676', + default: false, + description: 'Request to add the city' + } + ], + state: 'open', + locked: false, + assignees: [], + milestone: null, + comments: 0, + created_at: '2026-08-17T06:52:12Z', + updated_at: '2026-08-17T06:52:12Z', + closed_at: null, + assignee: null, + author_association: 'NONE', + issue_field_values: [], + type: null, + active_lock_reason: null, + sub_issues_summary: { total: 0, completed: 0, percent_completed: 0 }, + issue_dependencies_summary: { + blocked_by: 0, + total_blocked_by: 0, + blocking: 0, + total_blocking: 0 + }, + body: '### Country\n\nUS\n\n### Subdivision (optional)\n\nOH\n\n### City Name\n\nHuston\n\n### City Code\n\nUSHUS\n\n### Wikidata ID\n\nQ386802\n\n### Notes (optional)\n\n_No response_', + closed_by: null, + reactions: { + url: 'https://api.github.com/repos/iptv-org/database/issues/31989/reactions', + total_count: 0, + '+1': 0, + '-1': 0, + laugh: 0, + hooray: 0, + confused: 0, + heart: 0, + rocket: 0, + eyes: 0 + }, + timeline_url: 'https://api.github.com/repos/iptv-org/database/issues/31989/timeline', + performed_via_github_app: null, + state_reason: null, + pinned_comment: null } ] diff --git a/tests/commands/issue/validate.test.ts b/tests/commands/issue/validate.test.ts index 444111aa0a..22a3ebc682 100644 --- a/tests/commands/issue/validate.test.ts +++ b/tests/commands/issue/validate.test.ts @@ -1,10 +1,11 @@ +import issues from '../../__data__/input/issue/validate/issues' import { beforeEach, describe, it, expect } from 'vitest' -import issues from '../../__data__/input/issues' import { pathToFileURL } from 'node:url' import { execSync } from 'child_process' import * as fs from 'fs-extra' -const ENV_VAR = 'cross-env DATA_DIR=tests/__data__/input/data LOGS_DIR=tests/__data__/output/logs' +const ENV_VAR = + 'cross-env DATA_DIR=tests/__data__/input/issue/validate/data LOGS_DIR=tests/__data__/output/logs' beforeEach(() => { fs.emptyDirSync('tests/__data__/output') @@ -179,6 +180,23 @@ describe('issue:validate', () => { } }) + it('can handle logos:add request with duplicate', () => { + const body = issues.find(issue => issue.number === 31772)?.body + const cmd = `${ENV_VAR} npm run issue:validate --- --body="${body}" --labels="approved,logos:add"` + + if (process.env.DEBUG === 'true') console.log(cmd) + try { + const stdout = execSync(cmd, { encoding: 'utf8' }) + if (process.env.DEBUG === 'true') console.log(stdout) + process.exit(0) + } catch (error) { + if (process.env.DEBUG === 'true') console.log(error) + expect(content('tests/__data__/output/logs/errors.txt')).toBe( + content('tests/__data__/expected/issue/validate/logs/logos_add_duplicate.txt') + ) + } + }) + it('can handle logos:edit request', () => { const body = issues.find(issue => issue.number === 31786)?.body const cmd = `${ENV_VAR} npm run issue:validate --- --body="${body}" --labels="approved,logos:edit"` @@ -264,6 +282,23 @@ describe('issue:validate', () => { } }) + it('can handle cities:add request with duplicate', () => { + const body = issues.find(issue => issue.number === 31989)?.body + const cmd = `${ENV_VAR} npm run issue:validate --- --body="${body}" --labels="approved,cities:add"` + + if (process.env.DEBUG === 'true') console.log(cmd) + try { + const stdout = execSync(cmd, { encoding: 'utf8' }) + if (process.env.DEBUG === 'true') console.log(stdout) + process.exit(0) + } catch (error) { + if (process.env.DEBUG === 'true') console.log(error) + expect(content('tests/__data__/output/logs/errors.txt')).toBe( + content('tests/__data__/expected/issue/validate/logs/cities_add_duplicate.txt') + ) + } + }) + it('can handle cities:edit request', () => { const body = issues.find(issue => issue.number === 31789)?.body const cmd = `${ENV_VAR} npm run issue:validate --- --body="${body}" --labels="approved,cities:edit"`