|
1 | 1 | import { GraphQLClient, gql } from 'graphql-request'
|
2 | 2 | import { get } from 'lodash'
|
| 3 | +import { gte } from 'semver' |
3 | 4 |
|
| 5 | +import { deflate } from 'zlib' |
4 | 6 | import { errors } from './errors'
|
| 7 | +import { promisify } from 'util' |
| 8 | +import { logger } from './logger' |
| 9 | + |
| 10 | + |
| 11 | +const deflateAsync = promisify(deflate) |
5 | 12 |
|
6 | 13 | export namespace Utils {
|
7 | 14 | /**
|
8 | 15 | * Build image-report url and headers
|
9 | 16 | * @param payload
|
10 | 17 | */
|
11 | 18 | export async function buildUrlHeaders(payload: Record<string, string | undefined>): Promise<{ url: string, headers: { authorization: string } }> {
|
12 |
| - const esc = encodeURIComponent |
13 | 19 | const headers = { 'authorization': payload['CF_API_KEY']! }
|
14 | 20 | const runtimeName = payload['CF_RUNTIME_NAME']
|
15 | 21 | let host
|
| 22 | + let runtimeVersion |
16 | 23 | if (!runtimeName) {
|
17 | 24 | host = payload['CF_HOST']
|
18 | 25 | delete payload['CF_HOST']
|
19 | 26 | } else {
|
20 |
| - const platformHost = payload['CF_PLATFORM_URL'] |
21 |
| - host = await Utils.getRuntimeIngressHost(runtimeName, headers, platformHost) |
| 27 | + const platformHost = payload['CF_PLATFORM_URL'] || 'https://g.codefresh.io' |
| 28 | + const runtimeInfo = await Utils.getRuntimeInfo(runtimeName, headers, platformHost) |
| 29 | + host = runtimeInfo.ingressHost |
| 30 | + runtimeVersion = runtimeInfo.runtimeVersion |
22 | 31 | delete payload['CF_RUNTIME_NAME']
|
23 | 32 | delete payload['CF_PLATFORM_URL']
|
24 | 33 | }
|
25 | 34 | delete payload['CF_API_KEY']
|
26 |
| - const qs = Object.entries(payload).map(kv => `${esc(kv[0])}=${esc(kv[1] || '')}`).join('&') |
| 35 | + let qs |
| 36 | + const shouldCompressData = runtimeVersion && gte(removeReleaseCandidatePrefixFromRuntimeVersion(runtimeVersion), '0.1.33') |
| 37 | + if (shouldCompressData) { |
| 38 | + logger.info('Using new query string format') |
| 39 | + qs = await this.getQueryStringCompressed(payload) |
| 40 | + } else { |
| 41 | + qs = this.getQueryString(payload) |
| 42 | + } |
| 43 | + |
27 | 44 | const url = `${host}/app-proxy/api/image-report?${qs}`
|
28 | 45 | if (payload['CF_LOCAL']) {
|
29 | 46 | return { url: `${host}/api/image-report?${qs}`, headers }
|
30 | 47 | }
|
31 | 48 | return { url, headers }
|
32 | 49 | }
|
33 | 50 |
|
34 |
| - export async function getRuntimeIngressHost(runtimeName: string, headers: Record<string, string>, platformHost = 'https://g.codefresh.io'): Promise<string> { |
| 51 | + export async function getRuntimeInfo(runtimeName: string, headers: Record<string, string>, platformHost): Promise<{ ingressHost: string, runtimeVersion: string }> { |
35 | 52 | const graphQLClient = new GraphQLClient(`${platformHost}/2.0/api/graphql`, {
|
36 | 53 | headers
|
37 | 54 | })
|
38 | 55 |
|
39 | 56 | const getRuntimeIngressHostQuery = gql`
|
40 | 57 | query Runtime($name: String!) {
|
41 | 58 | runtime(name: $name) {
|
42 |
| - ingressHost |
| 59 | + ingressHost, |
| 60 | + runtimeVersion |
43 | 61 | }
|
44 | 62 | }`
|
45 | 63 |
|
46 | 64 | const res = await graphQLClient.request(getRuntimeIngressHostQuery, { name: runtimeName })
|
47 | 65 | const ingressHost = get(res, 'runtime.ingressHost')
|
| 66 | + const runtimeVersion = get(res, 'runtime.runtimeVersion', '') |
48 | 67 | if (!ingressHost) {
|
49 | 68 | const message = res.runtime ? `ingress host is not defined on your '${runtimeName}' runtime` : `runtime '${runtimeName}' does not exist`
|
50 | 69 | throw new errors.ValidationError(message)
|
51 | 70 | }
|
52 |
| - return ingressHost |
| 71 | + return { ingressHost, runtimeVersion } |
| 72 | + } |
| 73 | + |
| 74 | + export async function getQueryStringCompressed(payload: Record<string, string | undefined>): Promise<string> { |
| 75 | + logger.debug('Start encoding variables') |
| 76 | + const dockerfile = payload['CF_DOCKERFILE_CONTENT'] |
| 77 | + if (dockerfile) { |
| 78 | + const compressedDockerfile = await deflateAsync(Buffer.from(dockerfile, 'base64'), { level: 9, strategy: 0 }) |
| 79 | + payload['CF_DOCKERFILE_CONTENT'] = compressedDockerfile.toString('base64') |
| 80 | + } |
| 81 | + const qs = this.getQueryString(payload) |
| 82 | + const compressedPayload = await deflateAsync(Buffer.from(qs), { level: 9, strategy: 0 }) |
| 83 | + const data = compressedPayload.toString('base64') |
| 84 | + logger.debug('Variables successfully encoded') |
| 85 | + return `data=${encodeURIComponent(data)}` |
| 86 | + } |
| 87 | + |
| 88 | + export function getQueryString(payload: Record<string, string | undefined>) { |
| 89 | + return Object.entries(payload).map(kv => `${encodeURIComponent(kv[0])}=${encodeURIComponent(kv[1] || '')}`).join('&') |
| 90 | + } |
| 91 | + |
| 92 | + export function removeReleaseCandidatePrefixFromRuntimeVersion(runtimeVersion: string): string { |
| 93 | + const [ runtimeVersionWithoutReleaseCandidatePrefix ] = runtimeVersion.split('-') |
| 94 | + return runtimeVersionWithoutReleaseCandidatePrefix |
53 | 95 | }
|
54 | 96 |
|
55 | 97 | export function tryParseJson (str: string) {
|
|
0 commit comments