zuul/web/src/api.js

366 lines
8.7 KiB
JavaScript

// Copyright 2018 Red Hat, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import Axios from 'axios'
let authToken = undefined
export function setAuthToken(token) {
authToken = token
}
function getHomepageUrl() {
//
// Discover serving location from href.
//
// This is only needed for sub-directory serving. Serving the application
// from 'scheme://domain/' may simply default to 'scheme://domain/'
//
// Note that this is not enough for sub-directory serving,
// The static files location also needs to be adapted with the 'homepage'
// settings of the package.json file.
//
// This homepage url is used for the Router and Link resolution logic
//
let url = new URL(window.location.href)
if ('PUBLIC_URL' in process.env) {
url.pathname = process.env.PUBLIC_URL
} else {
url.pathname = ''
}
if (!url.pathname.endsWith('/')) {
url.pathname = url.pathname + '/'
}
return url.origin + url.pathname
}
function getZuulUrl() {
// Return the zuul root api absolute url
const ZUUL_API = process.env.REACT_APP_ZUUL_API
let apiUrl
if (ZUUL_API) {
// Api url set at build time, use it
apiUrl = ZUUL_API
} else {
// Api url is relative to homepage path
apiUrl = getHomepageUrl() + 'api/'
}
if (!apiUrl.endsWith('/')) {
apiUrl = apiUrl + '/'
}
if (!apiUrl.endsWith('/api/')) {
apiUrl = apiUrl + 'api/'
}
// console.log('Api url is ', apiUrl)
return apiUrl
}
const apiUrl = getZuulUrl()
function getStreamUrl(apiPrefix) {
const streamUrl = (apiUrl + apiPrefix)
.replace(/(http)(s)?:\/\//, 'ws$2://') + 'console-stream'
// console.log('Stream url is ', streamUrl)
return streamUrl
}
function getAuthToken() {
return authToken
}
function makeRequest(url, method, data) {
if (method === undefined) {
method = 'get'
}
// This performs a simple GET and tries to detect if CORS errors are
// due to proxy authentication errors.
const instance = Axios.create({
baseURL: apiUrl
})
if (authToken) {
instance.defaults.headers.common['Authorization'] = 'Bearer ' + authToken
}
const config = {method, url, data}
// First try the request as normal
let res = instance.request(config).catch(err => {
if (err.response === undefined) {
// This is either a Network, DNS, or CORS error, but we can't tell which.
// If we're behind an authz proxy, it's possible our creds have timed out
// and the CORS error is because we're getting a redirect.
// Apache mod_auth_mellon (and possibly other authz proxies) will avoid
// issuing a redirect if X-Requested-With is set to 'XMLHttpRequest' and
// will instead issue a 403. We can use this to detect that case.
instance.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'
let res2 = instance.request(config).catch(err2 => {
if (err2.response && err2.response.status === 403) {
// We might be getting a redirect or something else,
// so reload the page.
console.log('Received 403 after unknown error; reloading')
window.location.reload()
}
// If we're still getting an error, we don't know the cause,
// it could be a transient network error, so we won't reload, we'll just
// wait for it to clear.
throw (err2)
})
return res2
}
throw (err)
})
return res
}
// Direct APIs
function fetchInfo() {
return makeRequest('info')
}
function fetchComponents() {
return makeRequest('components')
}
function fetchTenantInfo(apiPrefix) {
return makeRequest(apiPrefix + 'info')
}
function fetchOpenApi() {
return Axios.get(getHomepageUrl() + 'openapi.yaml')
}
function fetchTenants() {
return makeRequest(apiUrl + 'tenants')
}
function fetchConfigErrors(apiPrefix) {
return makeRequest(apiPrefix + 'config-errors')
}
function fetchStatus(apiPrefix) {
return makeRequest(apiPrefix + 'status')
}
function fetchChangeStatus(apiPrefix, changeId) {
return makeRequest(apiPrefix + 'status/change/' + changeId)
}
function fetchFreezeJob(apiPrefix, pipelineName, projectName, branchName, jobName) {
return makeRequest(apiPrefix +
'pipeline/' + pipelineName +
'/project/' + projectName +
'/branch/' + branchName +
'/freeze-job/' + jobName)
}
function fetchBuild(apiPrefix, buildId) {
return makeRequest(apiPrefix + 'build/' + buildId)
}
function fetchBuilds(apiPrefix, queryString) {
let path = 'builds'
if (queryString) {
path += '?' + queryString.slice(1)
}
return makeRequest(apiPrefix + path)
}
function fetchBuildset(apiPrefix, buildsetId) {
return makeRequest(apiPrefix + 'buildset/' + buildsetId)
}
function fetchBuildsets(apiPrefix, queryString) {
let path = 'buildsets'
if (queryString) {
path += '?' + queryString.slice(1)
}
return makeRequest(apiPrefix + path)
}
function fetchPipelines(apiPrefix) {
return makeRequest(apiPrefix + 'pipelines')
}
function fetchProject(apiPrefix, projectName) {
return makeRequest(apiPrefix + 'project/' + projectName)
}
function fetchProjects(apiPrefix) {
return makeRequest(apiPrefix + 'projects')
}
function fetchJob(apiPrefix, jobName) {
return makeRequest(apiPrefix + 'job/' + jobName)
}
function fetchJobGraph(apiPrefix, projectName, pipelineName, branchName) {
return makeRequest(apiPrefix +
'pipeline/' + pipelineName +
'/project/' + projectName +
'/branch/' + branchName +
'/freeze-jobs')
}
function fetchJobs(apiPrefix) {
return makeRequest(apiPrefix + 'jobs')
}
function fetchLabels(apiPrefix) {
return makeRequest(apiPrefix + 'labels')
}
function fetchNodes(apiPrefix) {
return makeRequest(apiPrefix + 'nodes')
}
function fetchSemaphores(apiPrefix) {
return makeRequest(apiPrefix + 'semaphores')
}
function fetchAutoholds(apiPrefix) {
return makeRequest(apiPrefix + 'autohold')
}
function fetchAutohold(apiPrefix, requestId) {
return makeRequest(apiPrefix + 'autohold/' + requestId)
}
function fetchUserAuthorizations(apiPrefix) {
return makeRequest(apiPrefix + 'authorizations')
}
function dequeue(apiPrefix, projectName, pipeline, change) {
return makeRequest(
apiPrefix + 'project/' + projectName + '/dequeue',
'post',
{
pipeline: pipeline,
change: change,
}
)
}
function dequeue_ref(apiPrefix, projectName, pipeline, ref) {
return makeRequest(
apiPrefix + 'project/' + projectName + '/dequeue',
'post',
{
pipeline: pipeline,
ref: ref,
}
)
}
function enqueue(apiPrefix, projectName, pipeline, change) {
return makeRequest(
apiPrefix + 'project/' + projectName + '/enqueue',
'post',
{
pipeline: pipeline,
change: change,
}
)
}
function enqueue_ref(apiPrefix, projectName, pipeline, ref, oldrev, newrev) {
return makeRequest(
apiPrefix + 'project/' + projectName + '/enqueue',
'post',
{
pipeline: pipeline,
ref: ref,
oldrev: oldrev,
newrev: newrev,
}
)
}
function autohold(apiPrefix, projectName, job, change, ref,
reason, count, node_hold_expiration) {
return makeRequest(
apiPrefix + 'project/' + projectName + '/autohold',
'post',
{
change: change,
job: job,
ref: ref,
reason: reason,
count: count,
node_hold_expiration: node_hold_expiration,
}
)
}
function autohold_delete(apiPrefix, requestId) {
return makeRequest(
apiPrefix + '/autohold/' + requestId,
'delete'
)
}
function promote(apiPrefix, pipeline, changes) {
return makeRequest(
apiPrefix + '/promote',
'post',
{
pipeline: pipeline,
changes: changes,
}
)
}
export {
apiUrl,
getHomepageUrl,
getStreamUrl,
getAuthToken,
fetchChangeStatus,
fetchConfigErrors,
fetchStatus,
fetchBuild,
fetchBuilds,
fetchBuildset,
fetchBuildsets,
fetchFreezeJob,
fetchPipelines,
fetchProject,
fetchProjects,
fetchJob,
fetchJobGraph,
fetchJobs,
fetchLabels,
fetchNodes,
fetchOpenApi,
fetchSemaphores,
fetchTenants,
fetchInfo,
fetchComponents,
fetchTenantInfo,
fetchUserAuthorizations,
fetchAutoholds,
fetchAutohold,
autohold,
autohold_delete,
dequeue,
dequeue_ref,
enqueue,
enqueue_ref,
promote,
}