1+ const fetch = require ( 'node-fetch' ) ;
2+ const diff = require ( 'diff' ) ;
3+ const fs = require ( 'fs' ) . promises ;
4+ const path = require ( 'path' ) ;
5+ const githubIssues = require ( './githubIssues.js' ) ;
6+
7+ let log = console ;
8+
9+ const qNetworkReplyHeaderUrl = 'https://code.qt.io/cgit/qt/qtbase.git/plain/src/network/access/qnetworkreply.h' ;
10+ const issueTitleBase = 'QNetworkReply Error Code Update' ;
11+
12+ const checkForUpdate = async ( { github, core, context, dryRun } ) => {
13+ try
14+ {
15+ log = core ;
16+
17+ const { blobId, qNetworkReplyErrorCodes } = await fetchQNetworkReplyErrorCodeListFromGitHub ( github ) ;
18+ const blobIdShort = shortenId ( blobId ) ;
19+ const diffWithLastUsedVersion = await getDiffWithLastUsedVersion ( qNetworkReplyErrorCodes ) ;
20+ if ( ! diffWithLastUsedVersion ) {
21+ log . info ( 'QNetworkReply error codes list is still up to date' ) ;
22+ return ;
23+ }
24+ log . warning ( 'QNetworkReply error codes list is outdated!' ) ;
25+
26+ const existingGithubIssues = await githubIssues . searchForExistingGithubIssue ( { keywords : [ issueTitleBase , blobIdShort ] , github, context } ) ;
27+
28+ if ( existingGithubIssues . total_count === 0 ) {
29+ createNewGithubIssue ( { blobId, diffWithLastUsedVersion, github, context, dryRun } ) ;
30+ }
31+ else if ( existingGithubIssues . total_count === 1 ) {
32+ log . info ( 'An issue already exists for this update.' ) ;
33+ }
34+ else {
35+ log . warning ( `Multiple issues exist for the QNetworkReply error codes update with id ${ blobIdShort } :\n${ JSON . stringify ( existingGithubIssues , undefined , 4 ) } ` ) ;
36+ }
37+ }
38+ catch ( error ) {
39+ core . setFailed ( `Could not check for HTTP status codes updates: ${ error } ` ) ;
40+ throw error ;
41+ }
42+ } ;
43+
44+ const shortenId = id => {
45+ return id . substring ( 0 , 8 )
46+ } ;
47+
48+ const fetchQNetworkReplyErrorCodeListFromGitHub = async ( github ) => {
49+ const getContent = github . repos . getContent || github . repos . getContents ;
50+ const response = await getContent ( {
51+ owner : 'qt' ,
52+ repo : 'qtbase' ,
53+ path : 'src/network/access/qnetworkreply.h' ,
54+ ref : 'dev'
55+ } ) ;
56+ const blobId = response . data . sha ;
57+
58+ const qNetworkReplyHeaderSource = decodeRepoContent ( response . data ) ;
59+ const qNetworkReplyErrorCodes = extractQNetworkReplyErrorCodes ( qNetworkReplyHeaderSource ) ;
60+
61+ return { blobId, qNetworkReplyErrorCodes } ;
62+ } ;
63+
64+ const fetchQNetworkReplyErrorCodeListFromQt = async ( ) => {
65+ const response = await fetch ( qNetworkReplyHeaderUrl ) ;
66+ if ( ! response . ok ) {
67+ throw Error ( `Error fetching QNetworkReply header: ${ response . status } ${ response . statusText } ` ) ;
68+ }
69+ const qNetworkReplyHeaderSource = await response . text ( ) ;
70+
71+ return extractQNetworkReplyErrorCodes ( qNetworkReplyHeaderSource ) ;
72+ }
73+
74+ const decodeRepoContent = ( response ) => {
75+ try {
76+ return Buffer . from ( response . content , response . encoding ) . toString ( 'utf-8' ) ;
77+ }
78+ catch ( e ) {
79+ throw Error ( `Unsupported repository content encoding: ${ response . encoding } \nOriginal exception: ${ e } ` ) ;
80+ }
81+ } ;
82+
83+ const extractQNetworkReplyErrorCodes = ( qnetworkReplyHeaderSource ) => {
84+ const enumMatch = / e n u m N e t w o r k E r r o r { ( .* ?) } ; / s. exec ( qnetworkReplyHeaderSource ) ;
85+ if ( ! enumMatch ) {
86+ throw Error ( 'Could not extract NetworkError codes from QNetworkReply header' ) ;
87+ }
88+ const enums = enumMatch [ 1 ] . trim ( ) . replace ( / \/ \/ .* $ | [ \t ] + | \n \n + | , / mg, '' ) ;
89+ return enums ;
90+ }
91+
92+ const getDiffWithLastUsedVersion = async ( qNetworkReplyErrorCodes ) => {
93+ const pathToLastUsedVersion = path . resolve ( './.github/QNetworkReplyErroCodes.txt' ) ;
94+ const lastUsedVersion = await fs . readFile ( pathToLastUsedVersion , { encoding : 'utf-8' } ) ;
95+ if ( lastUsedVersion === qNetworkReplyErrorCodes ) {
96+ return null ;
97+ }
98+ const patch = diff . createPatch ( 'QNetworkReplyErroCodes.txt' , lastUsedVersion , qNetworkReplyErrorCodes ) ;
99+ return patch ;
100+ } ;
101+
102+ const createNewGithubIssue = async ( { blobId, diffWithLastUsedVersion, github, context, dryRun } ) => {
103+ const blobIdShort = shortenId ( blobId ) ;
104+ const title = `${ issueTitleBase } ${ blobIdShort } ` ;
105+ const body = 'The `QNetworkReply::NetworkError` codes list has been updated. \n' +
106+ 'See https://code.qt.io/cgit/qt/qtbase.git/log/src/network/access/qnetworkreply.h' + '\n\n' +
107+ '## Diff ##' + '\n' +
108+ '```diff' + '\n' +
109+ diffWithLastUsedVersion + '\n' +
110+ '```' ;
111+
112+ if ( dryRun ) {
113+ log . info ( `Would create issue:\n${ JSON . stringify ( { title, body } , null , 4 ) } ` ) ;
114+ }
115+ else {
116+ const newIssue = await githubIssues . createNewGithubIssue ( { title, body, github, context } ) ;
117+ log . info ( `Created issue #${ newIssue . number } : ${ newIssue . html_url } ` ) ;
118+ }
119+ } ;
120+
121+ const main = async ( ) => {
122+ try
123+ {
124+ const qnetworkReplyErrorCodes = await fetchQNetworkReplyErrorCodeListFromQt ( ) ;
125+ const patch = await getDiffWithLastUsedVersion ( qnetworkReplyErrorCodes ) ;
126+ if ( patch ) {
127+ log . log ( patch ) ;
128+ }
129+ else {
130+ log . log ( "Last used version is still up to date!" ) ;
131+ }
132+ }
133+ catch ( reason ) {
134+ log . error ( reason ) ;
135+ process . exitCode = - 1 ;
136+ } ;
137+ } ;
138+
139+ module . exports = checkForUpdate ;
140+
141+ if ( require . main === module ) {
142+ main ( ) ;
143+ }
0 commit comments