diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000..4b38075 --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,135 @@ +name: Docker image - IdentityServer + +on: + push: + branches: + - develop + - main + paths: + - src/** + - .github/workflows/docker-image.yml + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + branches: + - develop + - main + paths: + - src/** + - .github/workflows/docker-image.yml + workflow_dispatch: + inputs: + push_image: + description: Push the image to Docker Hub. + required: false + default: false + type: boolean + custom_tag: + description: Optional extra tag for a manual publication. + required: false + default: '' + type: string + +permissions: + contents: read + +concurrency: + group: docker-identityserver-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + build: + name: Build IdentityServer image + if: github.event_name != 'pull_request' || github.event.pull_request.draft == false + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + - name: Check out source + uses: actions/checkout@v6 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Validate build inputs + shell: bash + env: + BUILD_CONTEXT: ./src + DOCKERFILE: ./src/SenseNet.IdentityServer4.Web/Dockerfile + run: | + set -euo pipefail + + test -d "${BUILD_CONTEXT}" || { + echo "::error::Docker context does not exist: ${BUILD_CONTEXT}" + exit 1 + } + test -f "${DOCKERFILE}" || { + echo "::error::Dockerfile does not exist: ${DOCKERFILE}" + exit 1 + } + + - name: Resolve source version + id: source + shell: bash + env: + BRANCH_TAG: ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.pull_request.number) || github.ref_name }} + run: | + set -euo pipefail + + SOURCE_SHA="$(git rev-parse HEAD)" + SHORT_SHA="$(git rev-parse --short=8 HEAD)" + COMMIT_DATE="$(git show -s --format=%cd --date=format:%Y%m%d HEAD)" + VERSION_TAG="${COMMIT_DATE}-${SHORT_SHA}" + LEGACY_DATE="$(TZ=Europe/Budapest date +%Y.%m.%d)" + + case "${BRANCH_TAG}" in + main) + COMPATIBILITY_TAG="${LEGACY_DATE}" + ;; + *) + COMPATIBILITY_TAG="${BRANCH_TAG}.${LEGACY_DATE}" + ;; + esac + + echo "source_sha=${SOURCE_SHA}" >> "${GITHUB_OUTPUT}" + echo "branch_tag=${BRANCH_TAG}" >> "${GITHUB_OUTPUT}" + echo "version_tag=${VERSION_TAG}" >> "${GITHUB_OUTPUT}" + echo "compatibility_tag=${COMPATIBILITY_TAG}" >> "${GITHUB_OUTPUT}" + + - name: Set up Docker metadata + id: meta + uses: docker/metadata-action@v6 + with: + images: sensenetcsp/sn-identityserver + tags: | + type=raw,value=${{ steps.source.outputs.branch_tag }} + type=raw,value=${{ steps.source.outputs.compatibility_tag }} + type=raw,value=${{ steps.source.outputs.version_tag }} + type=raw,value=preview,enable=${{ github.event_name == 'push' && github.ref_name == 'develop' }} + type=raw,value=latest,enable=${{ github.event_name == 'push' && github.ref_name == 'main' }} + type=raw,value=${{ inputs.custom_tag }},enable=${{ github.event_name == 'workflow_dispatch' && inputs.custom_tag != '' }} + labels: | + org.opencontainers.image.source=https://github.com/${{ github.repository }} + org.opencontainers.image.revision=${{ steps.source.outputs.source_sha }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Log in to Docker Hub + if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.push_image) + uses: docker/login-action@v4 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and optionally push + uses: docker/build-push-action@v7 + with: + context: ./src + file: ./src/SenseNet.IdentityServer4.Web/Dockerfile + platforms: linux/amd64 + push: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.push_image) }} + pull: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha,scope=identityserver + cache-to: type=gha,mode=max,scope=identityserver diff --git a/docs/docker-image-workflow.md b/docs/docker-image-workflow.md new file mode 100644 index 0000000..54240eb --- /dev/null +++ b/docs/docker-image-workflow.md @@ -0,0 +1,36 @@ +# Docker image workflow + +The repository-owned `docker-image.yml` workflow builds the IdentityServer +image from `src/SenseNet.IdentityServer4.Web/Dockerfile` with `src` as the +Docker build context. It publishes `sensenetcsp/sn-identityserver` to Docker +Hub. + +Pushes to `develop` and `main` build and publish automatically. Pull requests +targeting either branch perform build-only validation and never log in or push. +Manual runs use the branch selected in GitHub's **Run workflow** dialog and do +not publish unless `push_image` is enabled. + +Published images receive the source branch tag, an immutable +`YYYYMMDD-shortSHA` tag, and the legacy TFS-compatible date tag: + +- `develop.YYYY.MM.DD` on `develop`; +- `YYYY.MM.DD` on `main`. + +Automatic `develop` publishes also update `preview`, while automatic `main` +publishes update `latest`. A manual publishing run may add a `custom_tag`. + +The workflow requires these repository secrets for publishing: + +- `DOCKERHUB_USERNAME` +- `DOCKERHUB_TOKEN` + +TFS definition 348 downloads the `Sn-Deployment` artifact only for generic +Docker build, tag, login, push, logout, and runner-cleanup scripts. Its active +IdentityServer build is a plain Docker build with this repository's Dockerfile +and `src` context; it has no active private-feed preparation or generated build +asset that must be reproduced here. + +The current Dockerfile's Node 14 installation was validated by a full pushless +build. The deleted `hotfix/node-version-in-dockerfile` remote branch contained +the same Node version and checksum already present on `develop`, so it is not +part of this migration.