Skip to content

Commit 927259f

Browse files
authored
Github Action for automatic validation of DB migrations in a CI pipeline (#1)
* feat: use default inputs * fail pipeline if response code is unsuccessful * allow downloading artifacts * provide migration details on failure
1 parent 29a0b96 commit 927259f

File tree

4 files changed

+156
-8
lines changed

4 files changed

+156
-8
lines changed

Dockerfile

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
FROM alpine:3.13
22

3+
RUN apk add --no-cache curl jq
4+
35
COPY entrypoint.sh /entrypoint.sh
46

57
ENTRYPOINT ["/entrypoint.sh"]

README.md

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1-
# Migration CI action
1+
# DB Migration checker action
22

3-
A GitHub action to run DB migrations with the DLE
3+
A GitHub action to run DB migrations with Database Lab Engine (DLE)
4+
5+
## Overview
6+
**Database Lab DB migration checker** is a tool to automatically validate migrations in the CI pipeline.
7+
8+
## Database Lab DB migration checker's benefits:
9+
- Check migrations as a part of a standard pipeline
10+
- Protect DLE from data stealing - run migrations in a protected environment
11+
- Protect logs and artifacts from being revealed
12+
13+
## How to use
14+
Check out the [Database Lab DB migrations checker documentation](https://postgres.ai/docs/db-migration-checker)

action.yml

+54-3
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,62 @@ inputs:
44
owner:
55
description: 'The owner of the repository to check'
66
required: true
7+
default: ${{ github.repository_owner }}
8+
repo:
9+
description: 'The repo to check'
10+
required: true
11+
default: ${{ github.event.repository.name }}
12+
ref:
13+
description: 'The input represents a ref parameter, which can be a SHA, branch, or tag'
14+
required: true
15+
default: ${{ github.ref }}
16+
pull_request:
17+
description: 'Link to the pull request'
18+
required: false
19+
default: ${{ github.event.pull_request.html_url }}
20+
compare:
21+
description: 'The compare link'
22+
required: false
23+
default: ${{ github.event.compare }}
24+
commit_sha:
25+
description: 'Commit SHA'
26+
required: false
27+
default: ${{ github.event.after }}
28+
author_name:
29+
description: 'Author name'
30+
required: false
31+
default: ${{ github.event.head_commit.author.name }}
32+
commands:
33+
description: 'List of commands to run DB migrations'
34+
required: true
35+
dbname:
36+
description: 'The database that the workflow is running with'
37+
required: false
38+
default: ""
39+
migration_envs:
40+
description: 'List of commands to run DB migrations'
41+
required: false
42+
download_artifacts:
43+
description: 'Option to download artifacts'
44+
required: false
45+
default: "false"
46+
47+
observation_interval:
48+
description: 'Observation interval'
49+
required: false
50+
default: "10"
51+
max_lock_duration:
52+
description: 'Max lock duration'
53+
required: false
54+
default: "10"
55+
max_duration:
56+
description: 'Max duration'
57+
required: false
58+
default: "3600"
59+
760
outputs:
8-
status:
61+
response:
962
description: 'The result of CI checks'
1063
runs:
1164
using: 'docker'
1265
image: 'Dockerfile'
13-
args:
14-
- ${{ inputs.owner }}

entrypoint.sh

+87-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,90 @@
11
#!/bin/sh -l
22

3-
echo "Owner $1"
3+
KEEP_CLONE=false
44

5-
status="OK"
6-
echo "::set-output name=status::$status"
5+
if [[ "${INPUT_DOWNLOAD_ARTIFACTS}" == "true" ]]; then
6+
KEEP_CLONE=true
7+
fi
8+
9+
JSON_DATA=$(jq -n -c \
10+
--arg owner "$INPUT_OWNER" \
11+
--arg repo "$INPUT_REPO" \
12+
--arg ref "$INPUT_REF" \
13+
--arg commands "$INPUT_COMMANDS" \
14+
--arg db_name "$INPUT_DBNAME" \
15+
--arg username "$GITHUB_ACTOR" \
16+
--arg username_full "$INPUT_AUTHOR_NAME" \
17+
--arg username_link "${GITHUB_SERVER_URL}/$GITHUB_ACTOR" \
18+
--arg branch "${GITHUB_HEAD_REF:-${GITHUB_REF##*/}}" \
19+
--arg branch_link "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/tree/${GITHUB_HEAD_REF:-${GITHUB_REF##*/}}" \
20+
--arg commit "${INPUT_COMMIT_SHA}" \
21+
--arg commit_link "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commit/${INPUT_COMMIT_SHA}" \
22+
--arg request_link "${INPUT_PULL_REQUEST}" \
23+
--arg diff_link "${INPUT_COMPARE}" \
24+
--arg migration_envs "$INPUT_MIGRATION_ENVS" \
25+
--arg observation_interval "$INPUT_OBSERVATION_INTERVAL" \
26+
--arg max_lock_duration "$INPUT_MAX_LOCK_DURATION" \
27+
--arg max_duration "$INPUT_MAX_DURATION" \
28+
--argjson keep_clone "$KEEP_CLONE" \
29+
'{source: {owner: $owner, repo: $repo, ref: $ref, branch: $branch, branch_link: $branch_link, commit: $commit, commit_link: $commit_link, request_link: $request_link, diff_link: $diff_link}, username: $username, username_full: $username_full, username_link: $username_link, db_name: $db_name, commands: $commands | rtrimstr("\n") | split("\n"), migration_envs: $migration_envs | rtrimstr("\n") | split("\n"), observation_config: { observation_interval: $observation_interval|tonumber, max_lock_duration: $max_lock_duration|tonumber, max_duration: $max_duration|tonumber}, keep_clone: $keep_clone}')
30+
31+
echo $JSON_DATA
32+
33+
response_code=$(curl --show-error --silent --location --request POST "${CI_ENDPOINT}/migration/run" --write-out "%{http_code}" \
34+
--header "Verification-Token: ${SECRET_TOKEN}" \
35+
--header 'Content-Type: application/json' \
36+
--output response.json \
37+
--data "${JSON_DATA}")
38+
39+
jq . response.json
40+
41+
if [[ $response_code -ne 200 ]]; then
42+
echo "Invalid status code given: ${response_code}"
43+
exit 1
44+
fi
45+
46+
status=$(jq -r '.session.result.status' response.json)
47+
48+
if [[ $status != "passed" ]]; then
49+
echo "Invalid status given: ${status}"
50+
exit 1
51+
fi
52+
53+
echo "::set-output name=response::$(cat response.json)"
54+
55+
clone_id=$(jq -r '.clone_id' response.json)
56+
session_id=$(jq -r '.session.session_id' response.json)
57+
58+
if [[ ! $KEEP_CLONE ]]; then
59+
exit 0
60+
fi
61+
62+
# Download artifacts
63+
mkdir artifacts
64+
65+
download_artifacts() {
66+
artifact_code=$(curl --show-error --silent "${CI_ENDPOINT}/artifact/download?artifact_type=$1&session_id=$2&clone_id=$3" --write-out "%{http_code}" \
67+
--header "Verification-Token: ${SECRET_TOKEN}" \
68+
--header 'Content-Type: application/json' \
69+
--output artifacts/$1)
70+
71+
if [[ $artifact_code -ne 200 ]]; then
72+
echo "Downloading $1, invalid status code given: ${artifact_code}"
73+
return
74+
fi
75+
76+
echo "Artifact \"$1\" has been downloaded to the artifacts directory"
77+
}
78+
79+
cat response.json | jq -c -r '.session.artifacts[]' | while read artifact; do
80+
download_artifacts $artifact $session_id $clone_id
81+
done
82+
83+
# Stop the running clone
84+
response_code=$(curl --show-error --silent "${CI_ENDPOINT}/artifact/stop?clone_id=${clone_id}" --write-out "%{http_code}" \
85+
--header "Verification-Token: ${SECRET_TOKEN}" \
86+
--header 'Content-Type: application/json')
87+
88+
if [[ $response_code -ne 200 ]]; then
89+
echo "Invalid status code given on destroy clone: ${artifact_code}"
90+
fi

0 commit comments

Comments
 (0)