Skip to content

Instantly share code, notes, and snippets.

@marcosborges
Last active December 4, 2020 22:42
Show Gist options
  • Save marcosborges/6621081f4096c6f2d491f11b3dc395b2 to your computer and use it in GitHub Desktop.
Save marcosborges/6621081f4096c6f2d491f11b3dc395b2 to your computer and use it in GitHub Desktop.
/*
* Copyright 2020 Spotify AB
*
* 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"
import { PublisherBase, PublisherOptions, PublisherResult } from './types';
import { GitApi } from 'azure-devops-node-api/GitApi';
import { GitRepositoryCreateOptions } from 'azure-devops-node-api/interfaces/GitInterfaces';
import { pushToRemoteUserPass } from './helpers';
import { JsonValue } from '@backstage/config';
import { RequiredTemplateValues } from '../templater';
export class AzurePublisher implements PublisherBase {
private readonly client: GitApi;
private readonly token: string;
constructor(client: GitApi, token: string) {
this.client = client;
this.token = token;
}
async publish({
values,
directory,
}: PublisherOptions): Promise<PublisherResult> {
const repo = await this.createRemote(values);
const remoteUrl = repo.remoteUrl || ''
await pushToRemoteUserPass(directory, remoteUrl, 'notempty', this.token);
const catalogInfoUrl = `${remoteUrl}?path=%2F.azuredevops%2Fcatalog-info.yaml`;
await this.setupPipeline(values, repo);
await this.setupLibrary(values, repo);
await this.protectBranch(values, repo);
return { remoteUrl, catalogInfoUrl };
}
private async createRemote(
values: RequiredTemplateValues & Record<string, JsonValue>,
) {
const [project, name] = values.storePath.split('/');
const createOptions: GitRepositoryCreateOptions = { name };
const repo = await this.client.createRepository(createOptions, project);
return repo || '';
}
private async setupPipeline(
values: RequiredTemplateValues & Record<string, JsonValue>,
repo: any
) {
console.log('ScaffolderSetupPipeline')
const [project, name] = values.storePath.split('/');
const setup = await this.setupPipelineApi(project, repo.id, name)
return setup;
}
private async setupLibrary(
values: RequiredTemplateValues & Record<string, JsonValue>,
repo: any
) {
console.log('setupLibrary')
const [project] = values.storePath.split('/');
await this.setupLibraryApi(project, repo)
}
private async protectBranch(
values: RequiredTemplateValues & Record<string, JsonValue>,
repo: any
) {
console.log('ScaffolderProtectBranch')
const [project] = values.storePath.split('/');
await this.protectBranchApi(project, "dev_integracao" , repo)
await this.protectBranchApi(project, "release" , repo)
await this.protectBranchApi(project, "master" , repo)
}
private async setupPipelineApi(projectId: string, repositoryId: any, name: string) {
console.log('projectId:' + projectId)
console.log('repositoryId:' + repositoryId)
console.log('name' + name)
const serviceName = name
const project = await this.getProjectApi(projectId)
console.log(project)
const body = {
variables: "",
triggers: [
{
branchFilters : [],
pathFilters : [],
settingsSourceType : 2,
batchChanges : true,
maxConcurrentBuildsPerBranch : 1,
triggerType : "continuousIntegration"
}
],
retentionRules: [
{
branches: [
"+refs/heads/*",
],
daysToKeep: 10,
minimumToKeep: 1,
deleteBuildRecord: true,
deleteTestResults: true,
},
],
buildNumberFormat: "$(date:yyyyMMdd)$(rev:.r)",
jobAuthorizationScope: 1,
jobTimeoutInMinutes: 60,
jobCancelTimeoutInMinutes: 5,
process: {
yamlFilename: ".azuredevops/pipeline-azure.yml",
type: 2,
},
repository: {
properties: {
labelSources: 6,
labelSourcesFormat: 0,
reportBuildStatus: true,
fetchDepth: 0,
cleanOptions: 3,
gitLfsSupport: false,
skipSyncSource: false,
checkoutNestedSubmodules: false,
},
id: repositoryId,
type: "TfsGit",
name: repositoryId,
defaultBranch: "refs/heads/dev_integracao",
clean: true,
checkoutSubmodules: false,
},
name: serviceName,
path: "\\hefesto\\",
type: 2,
project: {
id: project.id,
},
}
try {
console.log(`${this.client.baseUrl}/${projectId}/_apis/build/definitions?api-version=5.0`)
const response: any = await axios.post(
`${this.client.baseUrl}${projectId}/_apis/build/definitions?api-version=5.0`,
JSON.stringify(body),
this.getRequestOptions()
)
return response.status === 200 ? response.data : {}
} catch (error) {
console.log(error)
throw new Error("Error on setup the pipeline.")
}
}
private async protectBranchApi(projectId: string, branch: string, repository: any) {
const policyTypeId = "fa4e907d-c16b-4a4c-9dfa-4916e5d171ab"
const body = {
"isEnabled": true,
"isBlocking": true,
"type": {
"id": policyTypeId
},
"settings": {
"useSquashMerge": true,
"allowNoFastForward": true,
"allowSquash": true,
"allowRebase": true,
"allowRebaseMerge": true,
"scope": [{
"repositoryId": repository.id,
"refName": `refs/heads/${branch}`,
"matchKind": "exact"
}]
}
}
try {
await axios.post(
`${this.client.baseUrl}/${projectId}/_apis/policy/configurations?api-version=5.1-preview`,
JSON.stringify(body),
this.getRequestOptions()
)
} catch (error) {
throw new Error("Error on setup the pipeline.")
}
const policyTypeId2 = "fa4e907d-c16b-4a4c-9dfa-4906e5d171dd"
const body2 = {
"isEnabled": true,
"isBlocking": true,
"isDeleted":false,
"type": {
"id": policyTypeId2
},
"settings": {
"allowDownvotes":false,
"blockLastPusherVote":false,
"creatorVoteCounts":true,
"requireVoteOnLastIteration":false,
"resetOnSourcePush":false,
"resetRejectionsOnSourcePush":false,
"minimumApproverCount": (branch == "dev_integracao" ? 1 : 2),
"scope": [
{
"repositoryId": repository.id,
"refName": `refs/heads/${branch}`,
"matchKind": "exact"
}
]
}
}
try {
await axios.post(
`${this.client.baseUrl}/${projectId}/_apis/policy/configurations?api-version=5.1-preview`,
JSON.stringify(body2),
this.getRequestOptions()
)
} catch (error) {
throw new Error("Error on setup the pipeline.")
}
return true
}
private async setupLibraryApi(projectId: string, repository: any ) {
const body = {
"variables": {
"auto_created": {
"value": true
},
"name" : {
"value" : repository.name
},
"private_agent_pool" : {
"value" : "OnPrem-Pool"
},
"skip_sonarqube" : {
"value" : "false"
},
"skip_rdm" : {
"value" : "false"
}
},
"type": "Vsts",
"name": repository.name,
"description": `grupo de vars de configuração da esteira para o repositório: ${repository.name}`
}
try {
const response: any = await axios.post(
`${this.client.baseUrl}/${projectId}/_apis/distributedtask/variablegroups?api-version=5.0-preview.1`,
JSON.stringify(body),
this.getRequestOptions()
)
return response.status === 200 ? response.data : {}
} catch (error) {
throw new Error("Error on setup the pipeline.")
}
}
private async getProjectApi(name: string): Promise<any> {
console.log(`${this.client.baseUrl}_apis/projects/${name}`)
try {
const response: any = await axios.get(
`${this.client.baseUrl}/_apis/projects/${name}`,
this.getRequestOptions()
)
console.log(response)
return response.status === 200 ? response.data : {}
} catch (error) {
console.log(error)
return {}
}
}
private getRequestOptions() {
const token = Buffer.from(`:${this.token}`).toString("base64")
return {
headers: {
Authorization: `Basic ${token}`,
"Content-Type": "application/json",
},
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment