-
Notifications
You must be signed in to change notification settings - Fork 25
Expand file tree
/
Copy pathpipeline_generator.lib
More file actions
241 lines (215 loc) · 13.3 KB
/
Copy pathpipeline_generator.lib
File metadata and controls
241 lines (215 loc) · 13.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/bin/bash
function help {
echo ""
echo "Generates a $pipeline_type on $provider based on the given definition."
echo ""
echo "Common flags:"
echo " -c, --config-file [Required] Configuration file containing $pipeline_type definition."
echo " -n, --pipeline-name [Required] Name that will be set to the $pipeline_type."
echo " -d, --local-directory [Required] Local directory of your project."
echo " -a, --artifact-path Path to be persisted as an artifact after $pipeline_type execution, e.g. where the application stores logs or any other blob on runtime."
echo " -b, --target-branch Name of the branch to which the Pull Request will target. PR is not created if the flag is not provided."
[[ "$provider" != "gcloud" ]] && echo " -w Open the Pull Request on the web browser if it cannot be automatically merged. Requires -b flag."
echo ""
echo "Build $pipeline_type flags:"
echo " -l, --language [Required] Language or framework of the project."
echo " -t, --target-directory Target directory of build process. Takes precedence over the language/framework default one."
echo ""
echo "Test $pipeline_type flags:"
echo " -l, --language [Required] Language or framework of the project."
[ "$provider" == "azure-devops" ] && echo " --build-pipeline-name [Required] Build $pipeline_type name."
echo ""
echo "Quality $pipeline_type flags:"
echo " -l, --language [Required] Language or framework of the project."
echo " --sonar-url [Required] Sonarqube URL."
echo " --sonar-token [Required] Sonarqube token."
[ "$provider" == "azure-devops" ] && echo " --build-pipeline-name [Required] Build $pipeline_type name."
[ "$provider" == "azure-devops" ] && echo " --test-pipeline-name [Required] Test $pipeline_type name."
echo ""
[ "$provider" == "github" ] && echo ""
[ "$provider" == "github" ] && echo "CI pipeline flags"
[ "$provider" == "github" ] && echo " --build-pipeline-name [Required] Name of the job calling the build $pipeline_type."
[ "$provider" == "github" ] && echo " --test-pipeline-name Name of the job calling the test $pipeline_type."
[ "$provider" == "github" ] && echo " --quality-pipeline-name Name of the job calling the quality $pipeline_type."
[ "$provider" == "github" ] && echo ""
echo "Package pipeline flags:"
echo " -l, --language [Required, if dockerfile not set] Language or framework of the project."
echo " --dockerfile [Required, if language not set] Path from the root of the project to its Dockerfile. Takes precedence over the language/framework default one."
[ "$provider" == "azure-devops" ] && echo " --build-pipeline-name [Required] Build $pipeline_type name."
[ "$provider" == "azure-devops" ] && echo " --quality-pipeline-name [Required] Quality $pipeline_type name."
[ "$provider" == "github" ] && echo " --ci-pipeline-name [Required] CI $pipeline_type name."
echo " -i, --image-name [Required] Name (excluding tag) for the generated container image."
echo " -u, --registry-user [Required, unless AWS] Container registry login user."
echo " -p, --registry-password [Required, unless AWS] Container registry login password."
echo " --aws-access-key [Required, if AWS] AWS account access key ID. Takes precedence over registry credentials."
echo " --aws-secret-access-key [Required, if AWS] AWS account secret access key."
echo " --aws-region [Required, if AWS] AWS region for ECR."
echo ""
echo "Library package $pipeline_type flags:"
echo " -l, --language [Required] Language or framework of the project."
echo ""
echo "Azure AKS provisioning $pipeline_type flags:"
echo " --resource-group [Required] Name of the resource group for the cluster."
echo " --storage-account [Required] Name of the storage account for the cluster."
echo " --storage-container [Required] Name of the storage container where the Terraform state of the cluster will be stored."
echo " --rancher Install Rancher to manage the cluster."
echo ""
echo "AWS EKS provisioning $pipeline_type flags:"
echo " --cluster-name [Required] Name for the cluster."
echo " --s3-bucket [Required] Name of the S3 bucket where the Terraform state of the cluster will be stored."
echo " --s3-key-path [Required] Path within the S3 bucket where the Terraform state of the cluster will be stored."
echo " --aws-access-key [Required, on first run] AWS account access key ID."
echo " --aws-secret-access-key [Required, on first run] AWS account secret access key."
echo " --aws-region [Required, on first run] AWS region for provisioning resources."
echo " --rancher Install Rancher to manage the cluster."
echo ""
echo "Deploy $pipeline_type flags:"
echo ""
echo " --package-pipeline-name [Required] Package $pipeline_type name."
echo " --env-provision-pipeline-name [Required] Environment provisioning $pipeline_type name."
echo " --k8s-provider [Required] Kubernetes cluster provider name. Accepted values: EKS, AKS."
echo " --k8s-namespace [Required] Kubernetes namespace where the application will be deployed."
echo " --k8s-deploy-files-path [Required] Path from the root of the project to the YAML manifests directory."
echo " --k8s-image-pull-secret-name Name for the generated secret containing registry credentials. Required when using a private registry to host images."
echo ""
exit
}
function validateRegistryLoginCredentials {
# if the user chose to push to a registry and the user has not already given a password
# then prompt the user
if [ -v dockerUser ] && [ ! -v dockerPassword ]
then
read -rsp "Please enter Docker registry password..." dockerPassword
fi
if [ -v awsRegion ] && [ -v awsAccessKey ] && [ ! -v awsSecretAccessKey ]
then
read -rsp "Please enter AWS secret access key..." awsSecretAccessKey
fi
}
function ensurePathFormat {
currentDirectory=$(pwd)
# When necessary, converts a relative path into an absolute path, and a Windows-style path (e.g. "C:\Users" or C:/Users) into a
# Unix-style path using forward slashes (e.g. "/c/Users").
localDirectory=${localDirectory//'\'/"/"}
cd "${localDirectory}" || { echo -e "${red}Error: Local directory '${localDirectory}' does not exist. Check provided path (missing quotes?)."; exit 1; }
localDirectory=$(pwd)
# Return to initial directory
cd "$currentDirectory"
}
function importConfigFile {
# Import config file.
source $configFile
IFS=, read -ra flags <<< "$mandatoryFlags"
# Check if the config file was supplied.
if test -z "$configFile"
then
echo -e "${red}Error: $pipeline_type definition configuration file not specified." >&2
exit 2
fi
# Check if the required flags in the config file have been activated.
for flag in "${flags[@]}"
do
if test -z $flag
then
echo -e "${red}Error: Missing parameters, some flags are mandatory." >&2
echo -e "${red}Use -h or --help flag to display help." >&2
exit 2
fi
done
}
function checkInstallations {
# Check if Git is installed
if ! [ -x "$(command -v git)" ]; then
echo -e "${red}Error: Git is not installed." >&2
exit 127
fi
# Check if the CLI tool for the provider is installed
if ([ "$provider" == "github" ] && ! [ -x "$(command -v gh)" ]); then
echo -e "${red}Error: Github CLI is not installed." >&2
exit 127
elif ([ "$provider" == "azure-devops" ] && ! [ -x "$(command -v az)" ]); then
echo -e "${red}Error: Azure CLI is not installed." >&2
exit 127
fi
# Check if Python is installed
if ! [ -x "$(command -v python)" ]; then
echo -e "${red}Error: Python is not installed." >&2
exit 127
fi
}
function createNewBranch {
echo -e "${green}Creating the new branch: ${sourceBranch}..."
echo -ne ${white}
# Create the new branch.
cd "${localDirectory}"
git checkout -b ${sourceBranch}
}
function copyYAMLFile {
echo -e "${green}Copying the corresponding files into your directory..."
echo -ne ${white}
# Create .pipelines and scripts if they do not exist.
mkdir -p "${localDirectory}/$scriptFilePath"
# Generate pipeline YAML from template and put it in the repository.
# We cannot use a variable in the definition of resource in the pipeline so we have to use a placeholder to replace it with the value we need
commonEnvSubstList='${buildPipelineName} ${testPipelineName} ${qualityPipelineName} ${pipelineName} ${ciPipelineName} ${packagePipelineName}'
envsubst "${commonEnvSubstList} ${specificEnvSubstList}" < "${hangarPath}/${templatesPath}/${yamlFile}.template" > "${localDirectory}/${pipelinePath}/${yamlFile}"
# Check if an extra artifact to store is supplied.
if test -n "$artifactPath"
then
# Add the extra step to the YAML.
if [ "$provider" == "azure-devops" ]
then
cat "${hangarPath}/${commonTemplatesPath}/store-extra-path.yml" >> "${localDirectory}/${pipelinePath}/${yamlFile}"
elif [ "$provider" == "github" ]
then
# (in case of -a flag set) Here we replace a comment inside the template file by a step in Github Actions to upload an artifact
storeExtraPathContent="\n - name: Publish Additional Output Artifact\n uses: actions\/upload-artifact@v3\n with:\n name: additional-pipeline-output\n path: \"\${{ env.artifactPath }}\""
sed -i "s/# mark to insert step for additonal artifact #/$storeExtraPathContent\n/" "${localDirectory}/${pipelinePath}/${yamlFile}"
elif [ "$provider" == "gcloud" ]
then
# (in case of -a flag set) We first check if an artifact is already uploaded in this template,
# to know if we need to add an artifact to the list of uploaded artifact because there is/are already artifact(s) uploaded,
# or if we need to add the artifact section because there is not artifact uploaded yet
grep -e "^artifacts:" "${localDirectory}/${pipelinePath}/${yamlFile}" > /dev/null && storeExtraPathContent=" - additional_output_\${BUILD_ID}.tar" || storeExtraPathContent="\nartifacts:\n objects:\n location: gs:\/\/\${PROJECT_ID}_cloudbuild\/pipelinesArtifacts\/${pipelineName}\/commit_\${SHORT_SHA}\n paths:\n - additional_output_\${BUILD_ID}.tar"
# We replace the comment used to know where to add the lines defined is the line above
sed -i "s/# mark to insert entry in artifact for additonal artifact #/$storeExtraPathContent\n/" "${localDirectory}/${pipelinePath}/${yamlFile}"
# Then we add a step to the pipeline to create a tar of the additional artiact, we create a tar for 2 reasons:
# - Keep the permissions of the files as they are
# - In Gcloud, if you try to upload a folder and not a file, it fails
stepCreateTarArtifact="- name: \${_DOCKER_IMAGE_STEPS}\n args: ['tar', '-cf', 'additional_output_\${BUILD_ID}.tar', '\${_ARTIFACT_PATH}']"
sed -i "s/# mark to insert step for additonal artifact #/$stepCreateTarArtifact\n/" "${localDirectory}/${pipelinePath}/${yamlFile}"
fi
else
if [ "$provider" == "github" ] || [ "$provider" == "gcloud" ]
then
# If no -a flag set, we just remove the mark used to place the additional entries and step in the yaml
sed -i '/# mark to insert step for additonal artifact #/d' "${localDirectory}/${pipelinePath}/${yamlFile}"
sed -i '/# mark to insert entry in artifact for additonal artifact #/d' "${localDirectory}/${pipelinePath}/${yamlFile}"
fi
fi
}
function copyCommonScript {
echo -e "${green}Copying the script(s) common to any $pipeline_type files into your directory..."
echo -ne ${white}
! (ls "${hangarPath}/${commonTemplatesPath}"/*.sh) &> /dev/null || cp "${hangarPath}/${commonTemplatesPath}"/*.sh "${localDirectory}/${scriptFilePath}"
}
function commitCommonFiles {
echo -e "${green}Commiting and pushing into Git remote..."
echo -ne ${white}
# Move into the project's directory and pushing the template into the Azure DevOps repository.
cd "${localDirectory}"
# Add the YAML files.
git add "$pipelinePath" -f
# Git commit and push it into the repository.
# changing all files to be executable
find "$pipelinePath" -type f -name '*.sh' -exec git update-index --chmod=+x {} \;
git commit -m "Adding the source YAML"
git push -u origin ${sourceBranch}
}
function setTargetDirectory {
case $language in
node | angular) targetDirectory="./" ;;
quarkus*) targetDirectory="./target/" ;;
*) echo -e "${red}Error: Specified language '${language}' is not supported." >&2; exit 1
esac
}