-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathartifact.xml
351 lines (287 loc) · 17.3 KB
/
artifact.xml
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
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
<?xml version="1.0"?>
<!--
@file artifact.xml
Targets for managing Drupal code artifacts.
@see docs/artifacts.md
@see defaults.yml
Copyright 2018 Palantir.net, Inc.
-->
<project name="artifact" default="artifact-main">
<!--
Target: build-artifact
Build and deploy the application.
-->
<target name="artifact-main" hidden="true">
<!-- This property MUST be provided. -->
<fail unless="artifact.git.remote" message="The remote git repository must be configured in the 'artifact.git.remote' property." />
<!-- Defaults are set in defaults.yml -->
<fail unless="artifact.directory" />
<fail unless="artifact.prefix" />
<fail unless="artifact.git.remote_base_branch" />
<fail unless="artifact.git.remote_name" />
<fail unless="artifact.gitignore_template" />
<fail unless="artifact.readme_template" />
<!-- Get the current commit, branch, message, and tag so that they can be used to label the
resulting artifact and reset the repository after the artifact is built. -->
<exec command="git rev-parse HEAD" outputProperty="artifact.git.commit" checkreturn="true" />
<!-- @TODO Handle the case when this command outputs "HEAD". This happens when
building a repo from a detatched head state (e.g. you've checked out a tag),
and it causes pushing the artifact to fail because "HEAD" is not a branch you
can push to. -->
<exec command="git rev-parse --abbrev-ref HEAD" outputProperty="artifact.git.branch" checkreturn="true" />
<exec command="git log -1 --oneline" outputProperty="artifact.git.commit_message" />
<exec command="git describe --tags --exact-match" outputProperty="artifact.git.tag" returnProperty="artifact.git.no_tag" />
<!-- Create a temporary branch name based on the commit for building the artifact,
to avoid branch conflicts. -->
<property name="artifact.git.temporary_branch" value="artifact-${artifact.git.commit}" override="true" />
<!-- Prefix the repository tag so that we're not using the exact same tag on the
artifact and on the repository, to avoid confusion, especially when the
artifact is built on a branch of the development repository. -->
<property name="artifact.git.artifact_tag" value="${artifact.prefix}${artifact.git.tag}" override="true" />
<!-- If the remote branch isn't configured, use a remote branch based on the name
of the current branch. This won't overwrite the property value if it is
already set. -->
<property name="artifact.git.remote_branch" value="${artifact.prefix}${artifact.git.branch}" />
<phingcall target="artifact-safeToBuild" />
<phingcall target="artifact-initializeRepository" />
<phingcall target="artifact-setupBranch" />
<phingcall target="artifact-updateCode" />
<phingcall target="artifact-build" />
<phingcall target="artifact-commit" />
<phingcall target="artifact-finish" />
</target>
<target name="artifact-safeToBuild" hidden="true">
<!-- Make sure the caller is using a deployment environment. -->
<echo>Deploy environment: ${build.env}</echo>
<if>
<or>
<equals arg1="${build.env}" arg2="vagrant" />
<equals arg1="${build.env}" arg2="default" />
</or>
<then>
<echo level="error"> * Specify the 'build.env' property for your artifact; this is often 'acquia' or 'pantheon'</echo>
<property name="ready_to_build" value="n" />
</then>
</if>
<!-- Prevent an artifact from being built when there are changes that are not
committed to git, since those changes wouldn't be replicable in later builds.
-->
<exec command="git status --porcelain" outputProperty="modified_files" />
<if>
<not><equals arg1="${modified_files}" arg2="" /></not>
<then>
<echo>Repository status: dirty</echo>
<echo level="error"> * You have changes which must be committed before you may build an artifact.</echo>
<echo level="error"> * Modified files: ${modified_files}</echo>
<property name="ready_to_build" value="n" />
</then>
<else>
<echo>Repository status: clean</echo>
</else>
</if>
<!-- Check that our artifact directory either doesn't exist or is the right repo -->
<exec command="[ -d '${artifact.directory}' ] && git -C '${artifact.directory}' remote show ${artifact.git.remote_name} -n | grep '${artifact.git.remote}'" returnProperty="artifact_repo_has_remote.error" />
<if>
<not><available file="${artifact.directory}" type="dir" /></not>
<then><echo>Artifact repository: does not exist (will be created)</echo></then>
<elseif>
<and>
<available file="${artifact.directory}" type="dir" />
<not><available file="${artifact.directory}/.git" type="dir" /></not>
</and>
<then>
<echo>Artifact repository: ${artifact.directory} is not a git repository</echo>
<echo level="error"> * Directory '${artifact.directory}' exists but is not a git repository. Please move or delete before continuing.</echo>
<property name="ready_to_build" value="n" />
</then>
</elseif>
<elseif>
<!-- does git remote show origin -n | grep '${artifact.git.remote}' return the right status? -->
<equals arg1="${artifact_repo_has_remote.error}" arg2="1" />
<then>
<echo>Artifact repository: ${artifact.directory} has wrong remote configuration</echo>
<echo level="error"> * Directory '${artifact.directory}' exists but the '${artifact.git.remote_name}' remote is not ${artifact.git.remote}. Please move or delete before continuing.</echo>
<property name="ready_to_build" value="n" />
</then>
</elseif>
<else>
<echo>Artifact repository: ${artifact.directory}</echo>
<echo> ${artifact.git.remote_name}=${artifact.git.remote}</echo>
</else>
</if>
<echo>Destination branch: ${artifact.git.remote_branch}</echo>
<if>
<equals arg1="${ready_to_build}" arg2="n" />
<then>
<echo />
<fail msg="Build state" />
</then>
</if>
<echo>Ok, ready to build!</echo>
</target>
<target name="artifact-initializeRepository" hidden="true">
<fail unless="artifact.directory" />
<fail unless="artifact.git.remote" />
<!-- If there is no directory there, clone the repo. -->
<if>
<not><available file="${artifact.directory}/.git" type="dir" /></not>
<then>
<echo>Cloning the repository from ${artifact.git.remote}</echo>
<gitclone repository="${artifact.git.remote}" targetPath="${artifact.directory}" />
</then>
</if>
<!-- Wipe out any local customizations. -->
<exec dir="${artifact.directory}" command="chmod -R 750 ." checkreturn="true" logoutput="true" />
<exec dir="${artifact.directory}" command="git reset --hard" checkreturn="true" logoutput="true" />
<exec dir="${artifact.directory}" command="git checkout ${artifact.git.remote_base_branch}" checkreturn="true" />
<exec dir="${artifact.directory}" command="git clean -ffd" checkreturn="true" />
</target>
<target name="artifact-setupBranch" hidden="true">
<exec dir="${artifact.directory}" command="git fetch ${artifact.git.remote_name} ${artifact.git.remote_branch}" returnProperty="remote_fetch.error" />
<if>
<not><equals arg1="${remote_fetch.error}" arg2="0" /></not>
<then>
<echo>Remote branch does not exist. Creating '${artifact.git.remote_branch}' on remote repository...</echo>
<exec dir="${artifact.directory}" command="git fetch ${artifact.git.remote_name} ${artifact.git.remote_base_branch}" returnProperty="remote_fetch_base.error" />
<if>
<not><equals arg1="${remote_fetch_base.error}" arg2="0" /></not>
<then><fail msg="Failed to create remote branch: base branch '${artifact.git.remote_base_branch}' could not be fetched." /></then>
</if>
<!-- The 'remote branch' should only exist on the remote, so we create, push, then delete the local copy. -->
<exec dir="${artifact.directory}" command="git branch ${artifact.git.remote_branch} ${artifact.git.remote_name}/${artifact.git.remote_base_branch}" checkreturn="true" />
<exec dir="${artifact.directory}" command="git push ${artifact.git.remote_name} ${artifact.git.remote_branch}:${artifact.git.remote_branch}" checkreturn="true" />
<exec dir="${artifact.directory}" command="git branch -d ${artifact.git.remote_branch}" checkreturn="true" />
<echo>Remote branch '${artifact.git.remote_name}/${artifact.git.remote_branch}' created.</echo>
</then>
</if>
<!-- At this point, we should have the latest work from the remote destination
branch available locally. Now create a fresh, temporary branch for our
artifact work, to avoid naming conflicts and allow clean rebuilds. -->
<!-- If the build failed previously, there might be an abandoned branch for this build. -->
<exec dir="${artifact.directory}" command="git branch | grep ${artifact.git.temporary_branch} && git branch -D ${artifact.git.temporary_branch}" logoutput="true" />
<exec dir="${artifact.directory}" command="git branch ${artifact.git.temporary_branch} ${artifact.git.remote_name}/${artifact.git.remote_branch}" checkreturn="true" logoutput="true" />
<exec dir="${artifact.directory}" command="git checkout ${artifact.git.temporary_branch}" checkreturn="true" />
<echo>Building on temporary branch '${artifact.git.temporary_branch}'.</echo>
</target>
<target name="artifact-updateCode" hidden="true">
<!-- Sometimes files have read-only permissions that will cause issues when we
attempt to remove them. -->
<exec dir="${artifact.directory}" command="chmod -R 750 ." checkreturn="true" logoutput="true" />
<!-- Remove all the existing files so that we can install cleanly. -->
<delete includeemptydirs="true">
<fileset dir="${artifact.directory}" defaultexcludes="false" excludes=".git,.git/**" includes="**/*,**/.git,**/.git/**" />
</delete>
<!-- List all files that are checked in to git, then use the list to copy them all
into the artifact. -->
<tempfile property="tmpfile" destdir="${build.dir}/artifacts" />
<exec command="git ls-files" dir="${build.dir}" output="${tmpfile}" />
<copy todir="${artifact.directory}" overwrite="true" haltonerror="true">
<filelist dir="${build.dir}" listfile="${tmpfile}" />
</copy>
<delete file="${tmpfile}" />
<!-- Copy a template .gitignore specific to the artifact. -->
<copy file="${artifact.gitignore_template}" tofile="${artifact.directory}/.gitignore" overwrite="true">
<filterchain>
<expandproperties />
</filterchain>
</copy>
<!-- Copy a template README into the artifact. -->
<copy file="${artifact.readme_template}" tofile="${artifact.directory}/README.md" overwrite="true">
<filterchain>
<expandproperties />
</filterchain>
</copy>
</target>
<target name="artifact-build" hidden="true">
<echo>Installing composer dependencies in the artifact...</echo>
<composer command="install" composer="${composer.composer}">
<arg line="--no-interaction --no-dev --ignore-platform-reqs --working-dir=${artifact.directory}" />
</composer>
<echo>Deleting .git subdirectories added by Composer...</echo>
<delete includeemptydirs="true">
<fileset dir="${artifact.directory}" defaultexcludes="false" excludes=".gitignore,.git/,.git/**" includes="**/.gitignore,**/.git,**/.git/**" />
</delete>
<echo>Running 'phing build' in the artifact...</echo>
<!-- Run the build target for each drupal.sites.* property key. -->
<foreachkey prefix="drupal.sites" omitKeys="_defaults" target="artifact-build-one" keyParam="site_key" prefixParam="prefix" />
</target>
<target name="artifact-build-one" hidden="true">
<!--
- Override the Drupal root so that it is within the artifact directory.
- Override the "artifact mode" so that files managed with the
<includeresource /> task are copied into the artifact instead of symlinked.
-->
<phing target="build" phingfile="${phing.file}" inheritAll="false" dir="." haltonfailure="true">
<property name="build.site" value="${site_key}" />
<property name="drupal.root" value="${artifact.directory}/${drupal.root}" override="true" />
<property name="includeresource.mode" value="copy" override="true" />
</phing>
</target>
<target name="artifact-commit" hidden="true">
<!-- The 'allFiles' flag on the GitCommitTask does not add files that aren't already tracked by git. -->
<exec command="git add --all" dir="${artifact.directory}" />
<!-- Commit all changes to the artifact repository. -->
<gitcommit repository="${artifact.directory}" message="Drupal artifact build of ${artifact.git.commit_message}" allFiles="true" />
<!-- If this is a build of a tag, tag the artifact. -->
<if>
<equals arg1="${artifact.git.no_tag}" arg2="0" />
<then>
<gittag repository="${artifact.directory}" name="${artifact.git.artifact_tag}" annotate="true" message="Drupal artifact build of tag ${artifact.git.tag}." />
</then>
</if>
</target>
<target name="artifact-finish" hidden="true">
<selectone list="push,keep,discard" propertyName="artifact.result" message="Push artifact changes to the '${artifact.git.remote_branch}' branch?" />
<if>
<equals arg1="${artifact.result}" arg2="push" />
<then>
<!-- Push the changes, delete the temporary branch, and keep any tag that was created. -->
<phingcall target="artifact-push" />
<phingcall target="artifact-resetState" />
</then>
</if>
<if>
<equals arg1="${artifact.result}" arg2="keep" />
<then>
<!-- Keep the temporary branch, but delete any tag that was created, since if we run the artifact
generation again, the tag should be re-created against the regenerated artifact. -->
<phingcall target="artifact-cleanupTag" />
<echo>Artifact changes are in the temporary branch '${artifact.git.temporary_branch}'</echo>
</then>
</if>
<if>
<equals arg1="${artifact.result}" arg2="discard" />
<then>
<!-- Delete the temporary branch and any tag that was created. -->
<phingcall target="artifact-cleanupTag" />
<phingcall target="artifact-resetState" />
</then>
</if>
</target>
<target name="artifact-push" hidden="true">
<echo>Pushing changes.</echo>
<exec dir="${artifact.directory}" command="git push ${artifact.git.remote_name} ${artifact.git.temporary_branch}:${artifact.git.remote_branch}" checkreturn="true" />
<!-- If this is a build of a tag, push the new artifact tag. -->
<if>
<equals arg1="${artifact.git.no_tag}" arg2="0" />
<then>
<exec dir="${artifact.directory}" command="git push ${artifact.git.remote_name} ${artifact.git.artifact_tag}" checkreturn="true" />
</then>
</if>
</target>
<target name="artifact-cleanupTag" hidden="true">
<if>
<equals arg1="${artifact.git.no_tag}" arg2="0" />
<then>
<exec dir="${artifact.directory}" command="git tag -d ${artifact.git.artifact_tag}" checkreturn="true" logoutput="true" />
</then>
</if>
</target>
<target name="artifact-resetState" hidden="true">
<exec dir="${artifact.directory}" command="chmod -R 750 ." checkreturn="true" logoutput="true" />
<exec dir="${artifact.directory}" command="git reset --hard HEAD" checkreturn="true" logoutput="true" />
<exec dir="${artifact.directory}" command="git checkout ${artifact.git.remote_base_branch}" checkreturn="true" logoutput="true" />
<exec dir="${artifact.directory}" command="git clean -ffd" checkreturn="true" />
<exec dir="${artifact.directory}" command="git branch -D ${artifact.git.temporary_branch}" checkreturn="true" logoutput="true" />
</target>
</project>