diff --git a/src/css/grapesjs-plugins.scss b/src/css/grapesjs-plugins.scss index cfbd161a..329fff56 100644 --- a/src/css/grapesjs-plugins.scss +++ b/src/css/grapesjs-plugins.scss @@ -59,7 +59,40 @@ } // publication-ui +@keyframes pub-blink { + from { + opacity: 0.25; + } + to { + opacity: 1; + } +} + #publish-dialog { + .notice { + margin: 10px 0; + background-color: rgba(255, 166, 0, 0.2); + border-radius: 5px; + padding: 10px; + } + + progress { + width: 100%; + border-radius: 50px; + border: none; + height: 5px; + animation: pub-blink 0.33s infinite alternate; + background-color: $tertiaryColor; + } + + progress::-webkit-progress-bar { + background-color: $tertiaryColor; + } + + progress::-moz-progress-bar { + background-color: $tertiaryColor; + } + header { display: flex; align-items: center; diff --git a/src/ts/plugins/server/GitlabConnector.ts b/src/ts/plugins/server/GitlabConnector.ts index 97738bec..8f12c14d 100644 --- a/src/ts/plugins/server/GitlabConnector.ts +++ b/src/ts/plugins/server/GitlabConnector.ts @@ -211,6 +211,11 @@ export default class GitlabConnector implements StorageConnector { return encodeURIComponent(join(this.options.assetsFolder, path)) } + isUsingOfficialInstance(): boolean { + const gitlabDomainRegexp = /(^|\b)(gitlab\.com)($|\b)/ + return gitlabDomainRegexp.test(this.options.domain) + } + async createFile(session: GitlabSession, websiteId: WebsiteId, path: string, content: string, isBase64 = false): Promise { // Remove leading slash const safePath = path.replace(/^\//, '') @@ -293,7 +298,7 @@ export default class GitlabConnector implements StorageConnector { const headers = { 'Content-Type': 'application/json', } - if(method === 'GET' && body) { + if (method === 'GET' && body) { console.error('Gitlab API error (4) - GET request with body', {url, method, body, params}) } // With or without body @@ -312,9 +317,9 @@ export default class GitlabConnector implements StorageConnector { throw new ApiError(`Gitlab API error (0): ${e.message} ${e.code} ${e.name} ${e.type}`, 500) } let json: { message: string, error: string } | any - // Handle the case when the server returns an non-JSON response (e.g. 400 Bad Request) + // Handle the case when the server returns a non-JSON response (e.g. 400 Bad Request) const text = await response.text() - if(!response.ok) { + if (!response.ok) { if (text.includes('A file with this name doesn\'t exist')) { throw new ApiError('Gitlab API error (5): Not Found', 404) } else if (response.status === 401 && this.getSessionToken(session).token?.refresh_token) { diff --git a/src/ts/plugins/server/GitlabHostingConnector.ts b/src/ts/plugins/server/GitlabHostingConnector.ts index dc2ca073..077c549c 100644 --- a/src/ts/plugins/server/GitlabHostingConnector.ts +++ b/src/ts/plugins/server/GitlabHostingConnector.ts @@ -102,6 +102,21 @@ export default class GitlabHostingConnector extends GitlabConnector implements H job.message = 'Getting the deployment logs URL...' job.logs[0].push(job.message) const gitlabJobLogsUrl = await this.getGitlabJobLogsUrl(session, websiteId, job, { startJob, jobSuccess, jobError }, adminUrl, successTag) + // Because of the GitLab policy, this can be null (and we suggest the user to verify their account) + if (!gitlabJobLogsUrl) { + let errorMessage = 'Could not retrieve the deployment logs URL.' + + if (this.isUsingOfficialInstance()) { + const verifyURL = 'https://gitlab.com/-/identity_verification' + errorMessage += + `
+ If your GitLab account is recent, you may need to verify it here + in order to be able to use pipelines (this is GitLab's policy, not Silex's). +
` + } + + throw new Error(errorMessage) + } job.logs[0].push(`Deployment logs URL: ${gitlabJobLogsUrl}`) const message = `

Your website is now live here.

@@ -114,7 +129,7 @@ export default class GitlabHostingConnector extends GitlabConnector implements H console.error('Error during getting the website URLs:', error.message) jobError(job.jobId, `Failed to get the website URLs: ${error.message}`) } - } else if(status === JobStatus.ERROR) { + } else if (status === JobStatus.ERROR) { job.errors[0].push(message) jobError(job.jobId, message) } else { @@ -148,14 +163,15 @@ export default class GitlabHostingConnector extends GitlabConnector implements H } // waiting for the job corresponding to the current tag - async getGitlabJobLogsUrl(session: GitlabSession, websiteId: WebsiteId, job: PublicationJobData, { startJob, jobSuccess, jobError }: JobManager, projectUrl: string, tag): Promise { + async getGitlabJobLogsUrl(session: GitlabSession, websiteId: WebsiteId, job: PublicationJobData, { startJob, jobSuccess, jobError }: JobManager, projectUrl: string, tag): Promise { const t0 = Date.now() do { const jobs = await this.callApi(session, `api/v4/projects/${websiteId}/jobs`, 'GET') + if (!jobs.length) return null if (jobs[0].ref === tag) {return `${projectUrl}/-/jobs/${jobs[0].id}`} await setTimeout(waitTimeOut) } while ((Date.now() - t0) < this.options.timeOut) - + // failed in timelaps allowed (avoiding infinite loop) jobError(job.jobId, 'Failed to get job id') job.message = 'Unable to get job id' @@ -194,7 +210,8 @@ export default class GitlabHostingConnector extends GitlabConnector implements H jobError(job.jobId, `Failed to create new tag: ${error.message}`) return null } - // return new tag + + // Return new tag return newTag }