diff --git a/.github/actions/chart_releaser/action.yaml b/.github/actions/chart_releaser/action.yaml new file mode 100644 index 0000000..f276f7d --- /dev/null +++ b/.github/actions/chart_releaser/action.yaml @@ -0,0 +1,37 @@ +name: Release Charts + +on: + push: + branches: + - main + +jobs: + release: + # depending on default permission settings for your org (contents being read-only or read-write for workloads), you will have to add permissions + # see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token + permissions: + contents: write + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Install Helm + uses: azure/setup-helm@v4 + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + + - name: Run chart-releaser + uses: helm/chart-releaser-action@v1.6.0 + with: + charts_dir: helm + config: cr.yaml + env: + CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/actions/chart_releaser/cr.sh b/.github/actions/chart_releaser/cr.sh new file mode 100644 index 0000000..aac4119 --- /dev/null +++ b/.github/actions/chart_releaser/cr.sh @@ -0,0 +1,329 @@ +#!/usr/bin/env bash + +# Copyright The Helm Authors +# +# 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 +# +# https://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. + +set -o errexit +set -o nounset +set -o pipefail + +DEFAULT_CHART_RELEASER_VERSION=v1.6.0 + +show_help() { + cat < + + -h, --help Display help + -v, --version The chart-releaser version to use (default: $DEFAULT_CHART_RELEASER_VERSION)" + --config The path to the chart-releaser config file + -d, --charts-dir The charts directory (default: charts) + -o, --owner The repo owner + -r, --repo The repo name + -n, --install-dir The Path to install the cr tool + -i, --install-only Just install the cr tool + -s, --skip-packaging Skip the packaging step (run your own packaging before using the releaser) + --skip-existing Skip package upload if release exists + -l, --mark-as-latest Mark the created GitHub release as 'latest' (default: true) +EOF +} + +main() { + local version="$DEFAULT_CHART_RELEASER_VERSION" + local config= + local charts_dir=charts + local owner= + local repo= + local install_dir= + local install_only= + local skip_packaging= + local skip_existing= + local mark_as_latest=true + + parse_command_line "$@" + + : "${CR_TOKEN:?Environment variable CR_TOKEN must be set}" + + local repo_root + repo_root=$(git rev-parse --show-toplevel) + pushd "$repo_root" >/dev/null + + if [[ -z "$skip_packaging" ]]; then + echo 'Looking up latest tag...' + local latest_tag + latest_tag=$(lookup_latest_tag) + + echo "Discovering changed charts since '$latest_tag'..." + local changed_charts=() + readarray -t changed_charts <<<"$(lookup_changed_charts "$latest_tag")" + + if [[ -n "${changed_charts[*]}" ]]; then + install_chart_releaser + + rm -rf .cr-release-packages + mkdir -p .cr-release-packages + + rm -rf .cr-index + mkdir -p .cr-index + + for chart in "${changed_charts[@]}"; do + if [[ -d "$chart" ]]; then + package_chart "$chart" + else + echo "Nothing to do. No chart changes detected." + fi + done + + release_charts + update_index + echo "changed_charts=$( + IFS=, + echo "${changed_charts[*]}" + )" >changed_charts.txt + else + echo "Nothing to do. No chart changes detected." + echo "changed_charts=" >changed_charts.txt + fi + else + install_chart_releaser + rm -rf .cr-index + mkdir -p .cr-index + release_charts + update_index + fi + + echo "chart_version=${latest_tag}" >chart_version.txt + + popd >/dev/null +} + +parse_command_line() { + while :; do + case "${1:-}" in + -h | --help) + show_help + exit + ;; + --config) + if [[ -n "${2:-}" ]]; then + config="$2" + shift + else + echo "ERROR: '--config' cannot be empty." >&2 + show_help + exit 1 + fi + ;; + -v | --version) + if [[ -n "${2:-}" ]]; then + version="$2" + shift + else + echo "ERROR: '-v|--version' cannot be empty." >&2 + show_help + exit 1 + fi + ;; + -d | --charts-dir) + if [[ -n "${2:-}" ]]; then + charts_dir="$2" + shift + else + echo "ERROR: '-d|--charts-dir' cannot be empty." >&2 + show_help + exit 1 + fi + ;; + -o | --owner) + if [[ -n "${2:-}" ]]; then + owner="$2" + shift + else + echo "ERROR: '--owner' cannot be empty." >&2 + show_help + exit 1 + fi + ;; + -r | --repo) + if [[ -n "${2:-}" ]]; then + repo="$2" + shift + else + echo "ERROR: '--repo' cannot be empty." >&2 + show_help + exit 1 + fi + ;; + -n | --install-dir) + if [[ -n "${2:-}" ]]; then + install_dir="$2" + shift + fi + ;; + -i | --install-only) + if [[ -n "${2:-}" ]]; then + install_only="$2" + shift + fi + ;; + -s | --skip-packaging) + if [[ -n "${2:-}" ]]; then + skip_packaging="$2" + shift + fi + ;; + --skip-existing) + if [[ -n "${2:-}" ]]; then + skip_existing="$2" + shift + fi + ;; + -l | --mark-as-latest) + if [[ -n "${2:-}" ]]; then + mark_as_latest="$2" + shift + fi + ;; + *) + break + ;; + esac + + shift + done + + if [[ -z "$owner" ]]; then + echo "ERROR: '-o|--owner' is required." >&2 + show_help + exit 1 + fi + + if [[ -z "$repo" ]]; then + echo "ERROR: '-r|--repo' is required." >&2 + show_help + exit 1 + fi + + if [[ -z "$install_dir" ]]; then + local arch + arch=$(uname -m) + install_dir="$RUNNER_TOOL_CACHE/cr/$version/$arch" + fi + + if [[ -n "$install_only" ]]; then + echo "Will install cr tool and not run it..." + install_chart_releaser + exit 0 + fi +} + +install_chart_releaser() { + if [[ ! -d "$RUNNER_TOOL_CACHE" ]]; then + echo "Cache directory '$RUNNER_TOOL_CACHE' does not exist" >&2 + exit 1 + fi + + if [[ ! -d "$install_dir" ]]; then + mkdir -p "$install_dir" + + echo "Installing chart-releaser on $install_dir..." + curl -sSLo cr.tar.gz "https://github.com/helm/chart-releaser/releases/download/$version/chart-releaser_${version#v}_linux_amd64.tar.gz" + tar -xzf cr.tar.gz -C "$install_dir" + rm -f cr.tar.gz + fi + + echo 'Adding cr directory to PATH...' + export PATH="$install_dir:$PATH" +} + +lookup_latest_tag() { + git fetch --tags >/dev/null 2>&1 + latest_tag=$(git tag --sort=-creatordate | sed -n '2p') + + if [ -z "$latest_tag" ]; then + # If no tags are found, return the initial commit hash + git rev-list --max-parents=0 --first-parent HEAD + else + echo "$latest_tag" + fi +} + +filter_charts() { + while read -r chart; do + [[ ! -d "$chart" ]] && continue + local file="$chart/Chart.yaml" + if [[ -f "$file" ]]; then + echo "$chart" + else + echo "WARNING: $file is missing, assuming that '$chart' is not a Helm chart. Skipping." 1>&2 + fi + done +} + +lookup_changed_charts() { + local commit="$1" + + if [ -z "$commit" ]; then + # If no commit is given (i.e., no previous tag), consider all charts. + find "$charts_dir" -maxdepth 1 -type d | filter_charts + else + local changed_files + changed_files=$(git diff --find-renames --name-only "$commit" -- "$charts_dir") + + local depth=$(($(tr "/" "\n" <<<"$charts_dir" | sed '/^\(\.\)*$/d' | wc -l) + 1)) + local fields="1-${depth}" + + cut -d '/' -f "$fields" <<<"$changed_files" | uniq | filter_charts + fi +} + + +package_chart() { + local chart="$1" + + local args=("$chart" --package-path .cr-release-packages) + if [[ -n "$config" ]]; then + args+=(--config "$config") + fi + + echo "Packaging chart '$chart'..." + cr package "${args[@]}" +} + +release_charts() { + local args=(-o "$owner" -r "$repo" -c "$(git rev-parse HEAD)") + if [[ -n "$config" ]]; then + args+=(--config "$config") + fi + if [[ -n "$skip_existing" ]]; then + args+=(--skip-existing) + fi + if [[ "$mark_as_latest" = false ]]; then + args+=(--make-release-latest=false) + fi + + echo 'Releasing charts...' + cr upload "${args[@]}" +} + +update_index() { + local args=(-o "$owner" -r "$repo" --push) + if [[ -n "$config" ]]; then + args+=(--config "$config") + fi + + echo 'Updating charts repo index...' + cr index "${args[@]}" +} + +main "$@" \ No newline at end of file diff --git a/.github/actions/chart_releaser/cr.yaml b/.github/actions/chart_releaser/cr.yaml new file mode 100644 index 0000000..8ee6e3f --- /dev/null +++ b/.github/actions/chart_releaser/cr.yaml @@ -0,0 +1,4 @@ +owner: OpSecId +git-repo: trustdidweb-server-py +git-base-url: https://api.github.com/ +git-upload-url: https://uploads.github.com/ \ No newline at end of file diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..93826c7 --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,34 @@ + # For details on how this file works refer to: + # - https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +version: 2 +updates: + # Maintain dependencies for GitHub Actions + # - Check for updates once a week + # - Group all updates into a single PR + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + groups: + all-actions: + patterns: [ "*" ] + + # Maintain dependencies for Python Packages + - package-ecosystem: "pip" + directory: "/server" + schedule: + interval: "weekly" + day: "monday" + time: "04:00" + timezone: "Canada/Pacific" + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + + - package-ecosystem: "docker" + directory: "/server" + schedule: + interval: "weekly" + day: "monday" + time: "04:00" + timezone: "Canada/Pacific" diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..340fad8 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,90 @@ +name: Publish TDW Server Image +run-name: Publish TDW Server ${{ inputs.tag || github.event.release.tag_name }} Image +on: + release: + types: [published] + + workflow_dispatch: + inputs: + tag: + description: "Image tag" + required: true + type: string + platforms: + description: "Platforms - Comma separated list of the platforms to support." + required: true + default: linux/amd64 + type: string + ref: + description: "Optional - The branch, tag or SHA to checkout." + required: false + type: string + +env: + PLATFORMS: ${{ inputs.platforms || 'linux/amd64,linux/arm64' }} + +jobs: + publish-image: + if: github.repository_owner == 'OpSecId' + strategy: + fail-fast: false + + name: Publish TDW Server Image + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref || '' }} + + - name: Gather image info + id: info + run: | + echo "repo-owner=${GITHUB_REPOSITORY_OWNER,,}" >> $GITHUB_OUTPUT + + - name: Cache Docker layers + uses: actions/cache@v4 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to the GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Image Metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ghcr.io/${{ steps.info.outputs.repo-owner }}/trustdidweb-server-py + tags: | + type=raw,value=${{ inputs.tag || github.event.release.tag_name }} + + - name: Build and Push Image to ghcr.io + uses: docker/build-push-action@v5 + with: + push: true + context: . + file: docker/Dockerfile + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max + platforms: ${{ env.PLATFORMS }} + + # Temp fix + # https://github.com/docker/build-push-action/issues/252 + # https://github.com/moby/buildkit/issues/1896 + - name: Move cache + run: | + rm -rf /tmp/.buildx-cache + mv /tmp/.buildx-cache-new /tmp/.buildx-cache \ No newline at end of file