├── 5 ├── alpine │ ├── Dockerfile │ └── docker-entrypoint.sh └── debian │ ├── Dockerfile │ └── docker-entrypoint.sh ├── .github └── workflows │ └── ci.yml ├── LICENSE ├── README.md ├── generate-stackbrew-library.sh └── update.sh /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: GitHub CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | schedule: 7 | - cron: 0 0 * * 0 8 | 9 | defaults: 10 | run: 11 | shell: 'bash -Eeuo pipefail -x {0}' 12 | 13 | jobs: 14 | 15 | generate-jobs: 16 | name: Generate Jobs 17 | runs-on: ubuntu-latest 18 | outputs: 19 | strategy: ${{ steps.generate-jobs.outputs.strategy }} 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: docker-library/bashbrew@HEAD 23 | - id: generate-jobs 24 | name: Generate Jobs 25 | run: | 26 | strategy="$("$BASHBREW_SCRIPTS/github-actions/generate.sh")" 27 | echo "strategy=$strategy" >> "$GITHUB_OUTPUT" 28 | jq . <<<"$strategy" # sanity check / debugging aid 29 | 30 | test: 31 | needs: generate-jobs 32 | strategy: ${{ fromJson(needs.generate-jobs.outputs.strategy) }} 33 | name: ${{ matrix.name }} 34 | runs-on: ${{ matrix.os }} 35 | steps: 36 | - uses: actions/checkout@v4 37 | - name: Prepare Environment 38 | run: ${{ matrix.runs.prepare }} 39 | - name: Pull Dependencies 40 | run: ${{ matrix.runs.pull }} 41 | - name: Build ${{ matrix.name }} 42 | run: ${{ matrix.runs.build }} 43 | - name: History ${{ matrix.name }} 44 | run: ${{ matrix.runs.history }} 45 | - name: Test ${{ matrix.name }} 46 | run: ${{ matrix.runs.test }} 47 | - name: '"docker images"' 48 | run: ${{ matrix.runs.images }} 49 | -------------------------------------------------------------------------------- /5/alpine/Dockerfile: -------------------------------------------------------------------------------- 1 | # https://docs.ghost.org/faq/node-versions/ 2 | # https://github.com/nodejs/Release (looking for "LTS") 3 | FROM node:20-alpine3.22 4 | 5 | RUN apk add --no-cache \ 6 | # add "bash" for "[[" 7 | bash 8 | 9 | # grab gosu for easy step-down from root 10 | # https://github.com/tianon/gosu/releases 11 | ENV GOSU_VERSION 1.17 12 | RUN set -eux; \ 13 | \ 14 | apk add --no-cache --virtual .gosu-deps \ 15 | ca-certificates \ 16 | dpkg \ 17 | gnupg \ 18 | ; \ 19 | \ 20 | dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ 21 | wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ 22 | wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ 23 | \ 24 | # verify the signature 25 | export GNUPGHOME="$(mktemp -d)"; \ 26 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ 27 | gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ 28 | gpgconf --kill all; \ 29 | rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ 30 | \ 31 | # clean up fetch dependencies 32 | apk del --no-network .gosu-deps; \ 33 | \ 34 | chmod +x /usr/local/bin/gosu; \ 35 | # verify that the binary works 36 | gosu --version; \ 37 | gosu nobody true 38 | RUN set -eux; ln -svf gosu /usr/local/bin/su-exec; su-exec nobody true # backwards compatibility (TODO remove in Ghost 6+) 39 | 40 | ENV NODE_ENV production 41 | 42 | ENV GHOST_CLI_VERSION 1.27.0 43 | RUN set -eux; \ 44 | npm install -g "ghost-cli@$GHOST_CLI_VERSION"; \ 45 | npm cache clean --force 46 | 47 | ENV GHOST_INSTALL /var/lib/ghost 48 | ENV GHOST_CONTENT /var/lib/ghost/content 49 | 50 | ENV GHOST_VERSION 5.121.0 51 | 52 | RUN set -eux; \ 53 | mkdir -p "$GHOST_INSTALL"; \ 54 | chown node:node "$GHOST_INSTALL"; \ 55 | \ 56 | apkDel=; \ 57 | \ 58 | installCmd='gosu node ghost install "$GHOST_VERSION" --db mysql --dbhost mysql --no-prompt --no-stack --no-setup --dir "$GHOST_INSTALL"'; \ 59 | if ! eval "$installCmd"; then \ 60 | virtual='.build-deps-ghost'; \ 61 | apkDel="$apkDel $virtual"; \ 62 | apk add --no-cache --virtual "$virtual" g++ linux-headers make python3; \ 63 | eval "$installCmd"; \ 64 | fi; \ 65 | \ 66 | # Tell Ghost to listen on all ips and not prompt for additional configuration 67 | cd "$GHOST_INSTALL"; \ 68 | gosu node ghost config --no-prompt --ip '::' --port 2368 --url 'http://localhost:2368'; \ 69 | gosu node ghost config paths.contentPath "$GHOST_CONTENT"; \ 70 | \ 71 | # make a config.json symlink for NODE_ENV=development (and sanity check that it's correct) 72 | gosu node ln -s config.production.json "$GHOST_INSTALL/config.development.json"; \ 73 | readlink -f "$GHOST_INSTALL/config.development.json"; \ 74 | \ 75 | # need to save initial content for pre-seeding empty volumes 76 | mv "$GHOST_CONTENT" "$GHOST_INSTALL/content.orig"; \ 77 | mkdir -p "$GHOST_CONTENT"; \ 78 | chown node:node "$GHOST_CONTENT"; \ 79 | chmod 1777 "$GHOST_CONTENT"; \ 80 | \ 81 | # force install a few extra packages manually since they're "optional" dependencies 82 | # (which means that if it fails to install, like on ARM/ppc64le/s390x, the failure will be silently ignored and thus turn into a runtime error instead) 83 | # see https://github.com/TryGhost/Ghost/pull/7677 for more details 84 | cd "$GHOST_INSTALL/current"; \ 85 | # scrape the expected versions directly from Ghost/dependencies 86 | packages="$(node -p ' \ 87 | var ghost = require("./package.json"); \ 88 | var transform = require("./node_modules/@tryghost/image-transform/package.json"); \ 89 | [ \ 90 | "sharp@" + transform.optionalDependencies["sharp"], \ 91 | "sqlite3@" + ghost.optionalDependencies["sqlite3"], \ 92 | ].join(" ") \ 93 | ')"; \ 94 | if echo "$packages" | grep 'undefined'; then exit 1; fi; \ 95 | for package in $packages; do \ 96 | installCmd='gosu node yarn add "$package" --force'; \ 97 | if ! eval "$installCmd"; then \ 98 | # must be some non-amd64 architecture pre-built binaries aren't published for, so let's install some build deps and do-it-all-over-again 99 | virtualPackages='g++ make python3 py3-setuptools'; \ 100 | case "$package" in \ 101 | # TODO sharp@*) virtualPackages="$virtualPackages pkgconf vips-dev"; \ 102 | sharp@*) echo >&2 "sorry: libvips 8.12.1 in Alpine 3.15 is not new enough (8.12.2+) for sharp 0.30 😞"; continue ;; \ 103 | esac; \ 104 | virtual=".build-deps-${package%%@*}"; \ 105 | apkDel="$apkDel $virtual"; \ 106 | apk add --no-cache --virtual "$virtual" $virtualPackages; \ 107 | \ 108 | eval "$installCmd --build-from-source"; \ 109 | fi; \ 110 | done; \ 111 | \ 112 | if [ -n "$apkDel" ]; then \ 113 | apk del --no-network $apkDel; \ 114 | fi; \ 115 | \ 116 | gosu node yarn cache clean; \ 117 | gosu node npm cache clean --force; \ 118 | npm cache clean --force; \ 119 | rm -rv /tmp/yarn* /tmp/v8* 120 | 121 | WORKDIR $GHOST_INSTALL 122 | VOLUME $GHOST_CONTENT 123 | 124 | COPY docker-entrypoint.sh /usr/local/bin 125 | ENTRYPOINT ["docker-entrypoint.sh"] 126 | 127 | EXPOSE 2368 128 | CMD ["node", "current/index.js"] 129 | -------------------------------------------------------------------------------- /5/alpine/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # allow the container to be started with `--user` 5 | if [[ "$*" == node*current/index.js* ]] && [ "$(id -u)" = '0' ]; then 6 | find "$GHOST_CONTENT" \! -user node -exec chown node '{}' + 7 | exec gosu node "$BASH_SOURCE" "$@" 8 | fi 9 | 10 | if [[ "$*" == node*current/index.js* ]]; then 11 | baseDir="$GHOST_INSTALL/content.orig" 12 | for src in "$baseDir"/*/ "$baseDir"/themes/*; do 13 | src="${src%/}" 14 | target="$GHOST_CONTENT/${src#$baseDir/}" 15 | mkdir -p "$(dirname "$target")" 16 | if [ ! -e "$target" ]; then 17 | tar -cC "$(dirname "$src")" "$(basename "$src")" | tar -xC "$(dirname "$target")" 18 | fi 19 | done 20 | fi 21 | 22 | exec "$@" 23 | -------------------------------------------------------------------------------- /5/debian/Dockerfile: -------------------------------------------------------------------------------- 1 | # https://docs.ghost.org/faq/node-versions/ 2 | # https://github.com/nodejs/Release (looking for "LTS") 3 | FROM node:20-bookworm-slim 4 | 5 | # grab gosu for easy step-down from root 6 | # https://github.com/tianon/gosu/releases 7 | ENV GOSU_VERSION 1.17 8 | RUN set -eux; \ 9 | # save list of currently installed packages for later so we can clean up 10 | savedAptMark="$(apt-mark showmanual)"; \ 11 | apt-get update; \ 12 | apt-get install -y --no-install-recommends ca-certificates gnupg wget; \ 13 | rm -rf /var/lib/apt/lists/*; \ 14 | \ 15 | dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ 16 | wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ 17 | wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ 18 | \ 19 | # verify the signature 20 | export GNUPGHOME="$(mktemp -d)"; \ 21 | gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ 22 | gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ 23 | gpgconf --kill all; \ 24 | rm -rf "$GNUPGHOME" /usr/local/bin/gosu.asc; \ 25 | \ 26 | # clean up fetch dependencies 27 | apt-mark auto '.*' > /dev/null; \ 28 | [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \ 29 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ 30 | \ 31 | chmod +x /usr/local/bin/gosu; \ 32 | # verify that the binary works 33 | gosu --version; \ 34 | gosu nobody true 35 | 36 | ENV NODE_ENV production 37 | 38 | ENV GHOST_CLI_VERSION 1.27.0 39 | RUN set -eux; \ 40 | npm install -g "ghost-cli@$GHOST_CLI_VERSION"; \ 41 | npm cache clean --force 42 | 43 | ENV GHOST_INSTALL /var/lib/ghost 44 | ENV GHOST_CONTENT /var/lib/ghost/content 45 | 46 | ENV GHOST_VERSION 5.121.0 47 | 48 | RUN set -eux; \ 49 | mkdir -p "$GHOST_INSTALL"; \ 50 | chown node:node "$GHOST_INSTALL"; \ 51 | \ 52 | savedAptMark="$(apt-mark showmanual)"; \ 53 | aptPurge=; \ 54 | \ 55 | installCmd='gosu node ghost install "$GHOST_VERSION" --db mysql --dbhost mysql --no-prompt --no-stack --no-setup --dir "$GHOST_INSTALL"'; \ 56 | if ! eval "$installCmd"; then \ 57 | aptPurge=1; \ 58 | apt-get update; \ 59 | apt-get install -y --no-install-recommends g++ make python3; \ 60 | eval "$installCmd"; \ 61 | fi; \ 62 | \ 63 | # Tell Ghost to listen on all ips and not prompt for additional configuration 64 | cd "$GHOST_INSTALL"; \ 65 | gosu node ghost config --no-prompt --ip '::' --port 2368 --url 'http://localhost:2368'; \ 66 | gosu node ghost config paths.contentPath "$GHOST_CONTENT"; \ 67 | \ 68 | # make a config.json symlink for NODE_ENV=development (and sanity check that it's correct) 69 | gosu node ln -s config.production.json "$GHOST_INSTALL/config.development.json"; \ 70 | readlink -f "$GHOST_INSTALL/config.development.json"; \ 71 | \ 72 | # need to save initial content for pre-seeding empty volumes 73 | mv "$GHOST_CONTENT" "$GHOST_INSTALL/content.orig"; \ 74 | mkdir -p "$GHOST_CONTENT"; \ 75 | chown node:node "$GHOST_CONTENT"; \ 76 | chmod 1777 "$GHOST_CONTENT"; \ 77 | \ 78 | # force install a few extra packages manually since they're "optional" dependencies 79 | # (which means that if it fails to install, like on ARM/ppc64le/s390x, the failure will be silently ignored and thus turn into a runtime error instead) 80 | # see https://github.com/TryGhost/Ghost/pull/7677 for more details 81 | cd "$GHOST_INSTALL/current"; \ 82 | # scrape the expected versions directly from Ghost/dependencies 83 | packages="$(node -p ' \ 84 | var ghost = require("./package.json"); \ 85 | var transform = require("./node_modules/@tryghost/image-transform/package.json"); \ 86 | [ \ 87 | "sharp@" + transform.optionalDependencies["sharp"], \ 88 | "sqlite3@" + ghost.optionalDependencies["sqlite3"], \ 89 | ].join(" ") \ 90 | ')"; \ 91 | if echo "$packages" | grep 'undefined'; then exit 1; fi; \ 92 | for package in $packages; do \ 93 | installCmd='gosu node yarn add "$package" --force'; \ 94 | if ! eval "$installCmd"; then \ 95 | # must be some non-amd64 architecture pre-built binaries aren't published for, so let's install some build deps and do-it-all-over-again 96 | aptPurge=1; \ 97 | apt-get update; \ 98 | apt-get install -y --no-install-recommends g++ make python3; \ 99 | case "$package" in \ 100 | # TODO sharp@*) apt-get install -y --no-install-recommends libvips-dev ;; \ 101 | sharp@*) echo >&2 "sorry: libvips 8.10 in Debian bullseye is not new enough (8.12.2+) for sharp 0.30 😞"; continue ;; \ 102 | esac; \ 103 | \ 104 | eval "$installCmd --build-from-source"; \ 105 | fi; \ 106 | done; \ 107 | \ 108 | if [ -n "$aptPurge" ]; then \ 109 | apt-mark showmanual | xargs apt-mark auto > /dev/null; \ 110 | [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; \ 111 | apt-get purge -y --auto-remove; \ 112 | rm -rf /var/lib/apt/lists/*; \ 113 | fi; \ 114 | \ 115 | gosu node yarn cache clean; \ 116 | gosu node npm cache clean --force; \ 117 | npm cache clean --force; \ 118 | rm -rv /tmp/yarn* /tmp/v8* 119 | 120 | WORKDIR $GHOST_INSTALL 121 | VOLUME $GHOST_CONTENT 122 | 123 | COPY docker-entrypoint.sh /usr/local/bin 124 | ENTRYPOINT ["docker-entrypoint.sh"] 125 | 126 | EXPOSE 2368 127 | CMD ["node", "current/index.js"] 128 | -------------------------------------------------------------------------------- /5/debian/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # allow the container to be started with `--user` 5 | if [[ "$*" == node*current/index.js* ]] && [ "$(id -u)" = '0' ]; then 6 | find "$GHOST_CONTENT" \! -user node -exec chown node '{}' + 7 | exec gosu node "$BASH_SOURCE" "$@" 8 | fi 9 | 10 | if [[ "$*" == node*current/index.js* ]]; then 11 | baseDir="$GHOST_INSTALL/content.orig" 12 | for src in "$baseDir"/*/ "$baseDir"/themes/*; do 13 | src="${src%/}" 14 | target="$GHOST_CONTENT/${src#$baseDir/}" 15 | mkdir -p "$(dirname "$target")" 16 | if [ ! -e "$target" ]; then 17 | tar -cC "$(dirname "$src")" "$(basename "$src")" | tar -xC "$(dirname "$target")" 18 | fi 19 | done 20 | fi 21 | 22 | exec "$@" 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Docker, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # https://github.com/docker-library/ghost 2 | 3 | ## Maintained by: [the Docker Community](https://github.com/docker-library/ghost) 4 | 5 | This is the Git repo of the [Docker "Official Image"](https://github.com/docker-library/official-images#what-are-official-images) for [`ghost`](https://hub.docker.com/_/ghost/) (not to be confused with any official `ghost` image provided by `ghost` upstream). See [the Docker Hub page](https://hub.docker.com/_/ghost/) for the full readme on how to use this Docker image and for information regarding contributing and issues. 6 | 7 | The [full image description on Docker Hub](https://hub.docker.com/_/ghost/) is generated/maintained over in [the docker-library/docs repository](https://github.com/docker-library/docs), specifically in [the `ghost` directory](https://github.com/docker-library/docs/tree/master/ghost). 8 | 9 | ## See a change merged here that doesn't show up on Docker Hub yet? 10 | 11 | For more information about the full official images change lifecycle, see [the "An image's source changed in Git, now what?" FAQ entry](https://github.com/docker-library/faq#an-images-source-changed-in-git-now-what). 12 | 13 | For outstanding `ghost` image PRs, check [PRs with the "library/ghost" label on the official-images repository](https://github.com/docker-library/official-images/labels/library%2Fghost). For the current "source of truth" for [`ghost`](https://hub.docker.com/_/ghost/), see [the `library/ghost` file in the official-images repository](https://github.com/docker-library/official-images/blob/master/library/ghost). 14 | 15 | 16 | -------------------------------------------------------------------------------- /generate-stackbrew-library.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eu 3 | 4 | declare -A aliases=( 5 | [5]='latest' 6 | ) 7 | defaultVariant='debian' 8 | 9 | self="$(basename "$BASH_SOURCE")" 10 | cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" 11 | 12 | versions=( */ ) 13 | versions=( "${versions[@]%/}" ) 14 | 15 | # sort version numbers with highest first 16 | IFS=$'\n'; versions=( $(echo "${versions[*]}" | sort -rV) ); unset IFS 17 | 18 | # get the most recent commit which modified any of "$@" 19 | fileCommit() { 20 | git log -1 --format='format:%H' HEAD -- "$@" 21 | } 22 | 23 | # get the most recent commit which modified "$1/Dockerfile" or any file COPY'd from "$1/Dockerfile" 24 | dirCommit() { 25 | local dir="$1"; shift 26 | ( 27 | cd "$dir" 28 | fileCommit \ 29 | Dockerfile \ 30 | $(git show HEAD:./Dockerfile | awk ' 31 | toupper($1) == "COPY" { 32 | for (i = 2; i < NF; i++) { 33 | print $i 34 | } 35 | } 36 | ') 37 | ) 38 | } 39 | 40 | getArches() { 41 | local repo="$1"; shift 42 | local officialImagesBase="${BASHBREW_LIBRARY:-https://github.com/docker-library/official-images/raw/HEAD/library}/" 43 | 44 | local parentRepoToArchesStr 45 | parentRepoToArchesStr="$( 46 | find -name 'Dockerfile' -exec awk -v officialImagesBase="$officialImagesBase" ' 47 | toupper($1) == "FROM" && $2 !~ /^('"$repo"'|scratch|.*\/.*)(:|$)/ { 48 | printf "%s%s\n", officialImagesBase, $2 49 | } 50 | ' '{}' + \ 51 | | sort -u \ 52 | | xargs -r bashbrew cat --format '["{{ .RepoName }}:{{ .TagName }}"]="{{ join " " .TagEntry.Architectures }}"' 53 | )" 54 | eval "declare -g -A parentRepoToArches=( $parentRepoToArchesStr )" 55 | } 56 | getArches 'ghost' 57 | 58 | cat <<-EOH 59 | # this file is generated via https://github.com/docker-library/ghost/blob/$(fileCommit "$self")/$self 60 | 61 | Maintainers: Tianon Gravi (@tianon), 62 | Joseph Ferguson (@yosifkit), 63 | Austin Burdine (@acburdine) 64 | GitRepo: https://github.com/docker-library/ghost.git 65 | EOH 66 | 67 | # prints "$2$1$3$1...$N" 68 | join() { 69 | local sep="$1"; shift 70 | local out; printf -v out "${sep//%/%%}%s" "$@" 71 | echo "${out#$sep}" 72 | } 73 | 74 | for version in "${versions[@]}"; do 75 | for variant in debian alpine; do 76 | commit="$(dirCommit "$version/$variant")" 77 | 78 | fullVersion="$(git show "$commit":"$version/$variant/Dockerfile" | awk '$1 == "ENV" && $2 == "GHOST_VERSION" { print $3; exit }')" 79 | 80 | versionAliases=() 81 | while [ "$fullVersion" != "$version" -a "${fullVersion%[.-]*}" != "$fullVersion" ]; do 82 | versionAliases+=( $fullVersion ) 83 | fullVersion="${fullVersion%[.-]*}" 84 | done 85 | versionAliases+=( 86 | $version 87 | ${aliases[$version]:-} 88 | ) 89 | 90 | if [ "$variant" = "$defaultVariant" ]; then 91 | variantAliases=( "${versionAliases[@]}" ) 92 | else 93 | variantAliases=( "${versionAliases[@]/%/-$variant}" ) 94 | variantAliases=( "${variantAliases[@]//latest-/}" ) 95 | fi 96 | 97 | variantParent="$(awk 'toupper($1) == "FROM" { print $2 }' "$version/$variant/Dockerfile")" 98 | variantArches="${parentRepoToArches[$variantParent]}" 99 | 100 | if [ "$variant" = 'alpine' ]; then 101 | # ERROR: unsatisfiable constraints: 102 | # vips-dev (missing): 103 | variantArches="$(sed -e 's/ ppc64le / /g' -e 's/ s390x / /g' <<<" $variantArches ")" 104 | fi 105 | 106 | echo 107 | cat <<-EOE 108 | Tags: $(join ', ' "${variantAliases[@]}") 109 | Architectures: $(join ', ' $variantArches) 110 | GitCommit: $commit 111 | Directory: $version/$variant 112 | EOE 113 | done 114 | done 115 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" 5 | 6 | versions=( "$@" ) 7 | if [ ${#versions[@]} -eq 0 ]; then 8 | versions=( */ ) 9 | fi 10 | versions=( "${versions[@]%/}" ) 11 | 12 | allVersions="$( 13 | git ls-remote --tags https://github.com/TryGhost/Ghost.git \ 14 | | sed -rne 's!^.*\trefs/tags/v?|\^\{\}$!!g; /^[0-9][.][0-9]+/p' \ 15 | | sort -ruV 16 | )" 17 | 18 | cliVersion="$( 19 | git ls-remote --tags https://github.com/TryGhost/Ghost-CLI.git \ 20 | | sed -rne 's!^.*\trefs/tags/v?|\^\{\}$!!g; /^[0-9][.][0-9]+/p' \ 21 | | grep -vE -- '-(alpha|beta|rc)' \ 22 | | sort -ruV \ 23 | | head -n1 24 | )" 25 | 26 | for version in "${versions[@]}"; do 27 | rcVersion="${version%-rc}" 28 | rcGrepV='-v' 29 | if [ "$rcVersion" != "$version" ]; then 30 | rcGrepV= 31 | fi 32 | rcGrepV+=' -E' 33 | rcGrepExpr='alpha|beta|rc' 34 | 35 | fullVersion="$( 36 | echo "$allVersions" \ 37 | | grep -E "^${rcVersion}([.-]|$)" \ 38 | | grep $rcGrepV -- "$rcGrepExpr" \ 39 | | head -1 40 | )" 41 | if [ -z "$fullVersion" ]; then 42 | echo >&2 "error: cannot determine full version for '$version'" 43 | exit 1 44 | fi 45 | 46 | ( 47 | set -x 48 | sed -ri \ 49 | -e 's/^(ENV GHOST_VERSION) .*/\1 '"$fullVersion"'/' \ 50 | -e 's/^(ENV GHOST_CLI_VERSION) .*/\1 '"$cliVersion"'/' \ 51 | "$version"/*/Dockerfile 52 | ) 53 | done 54 | --------------------------------------------------------------------------------