diff --git a/.github/RELEASE_CHECKLIST.md b/.github/RELEASE_CHECKLIST.md new file mode 100644 index 000000000..250b8a667 --- /dev/null +++ b/.github/RELEASE_CHECKLIST.md @@ -0,0 +1,25 @@ +# FerretDB's DocumentDB Release Checklist + +## Preparation + +1. Create draft release on GitHub to see a list of merged PRs. +2. Update CHANGELOG.md manually. It will point to versions of DocumentDB and FerretDB that are not released yet. +3. Update `packaging/debian_files/changelog`. +4. Send PR with changes, merge it. + +## Git tag + +1. Make a signed tag with `git tag -s --cleanup=verbatim vX.Y.Z-ferretdb-A.B.C(-p)` (like `v0.103.0-ferretdb-2.2.0-beta.1`), + where `X.Y.Z` is the SemVar formatted version of DocumentDB (like `0.103.0`), + and `A.B.C(-p)` is the compatible FerretDB version (like `2.2.0-beta.1`). +2. Check `git status` output. +3. Push it! + +## Release + +1. Find [Packages CI build](https://github.com/FerretDB/documentdb/actions/workflows/ferretdb_packages.yml?query=event%3Apush) + for the tag to release. +2. Check Docker images. +3. Upload `.deb` packages to the draft release. +4. Update release notes with the content of CHANGELOG.md. +5. Publish release on GitHub. diff --git a/.github/containers/Build-Ubuntu/Dockerfile b/.github/containers/Build-Ubuntu/Dockerfile index db2d9494c..69c82aa09 100644 --- a/.github/containers/Build-Ubuntu/Dockerfile +++ b/.github/containers/Build-Ubuntu/Dockerfile @@ -130,4 +130,4 @@ WORKDIR /home/documentdb LABEL org.opencontainers.image.source=https://github.com/microsoft/documentdb LABEL org.opencontainers.image.description="DocumentDB ubuntu build image" -LABEL org.opencontainers.image.licenses=MIT \ No newline at end of file +LABEL org.opencontainers.image.licenses=MIT diff --git a/.github/mergify.yml b/.github/mergify.yml new file mode 100644 index 000000000..e722a16b2 --- /dev/null +++ b/.github/mergify.yml @@ -0,0 +1,27 @@ +--- +# see https://docs.mergify.com/ + +pull_request_rules: + - name: "Assign PRs" + conditions: + - "-closed" + - "#assignee = 0" + actions: + assign: + add_users: ["{{ author }}"] + + - name: "Add label on conflicts" + conditions: + - "conflict" + actions: + comment: + message: "@{{author}} this pull request has merge conflicts." + label: + add: [conflict] + + - name: "Remove label when conflicts were resolved" + conditions: + - "-conflict" + actions: + label: + remove: [conflict] diff --git a/.github/settings.yml b/.github/settings.yml new file mode 100644 index 000000000..9edfd2909 --- /dev/null +++ b/.github/settings.yml @@ -0,0 +1,34 @@ +--- +# https://github.com/repository-settings/app + +repository: + allow_squash_merge: true + allow_merge_commit: true + allow_rebase_merge: false + allow_auto_merge: true + allow_update_branch: true + delete_branch_on_merge: true + enable_automated_security_fixes: true + enable_vulnerability_alerts: true + +# https://docs.github.com/en/rest/issues/labels +labels: + - name: conflict + color: "#FF0000" + description: PRs that have merge conflicts + + - name: deps + color: "#D4C5F9" + description: PRs that update dependencies + + - name: not ready + color: "#000000" + description: Issues that are not ready to be worked on; PRs that should skip CI + + - name: packages + color: "#9B022C" + description: PRs that should build packages + + - name: trust + color: "#00FF00" + description: PRs that can access Actions secrets diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 25af6322e..d0b37aa13 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -54,7 +54,7 @@ jobs: postgresql-15-cron \ postgresql-15-pgvector \ postgresql-15-postgis-3 \ - postgresql-15-rum + postgresql-15-rum export CLEAN_SETUP=1 export INSTALL_DEPENDENCIES_ROOT=/tmp/install_setup mkdir -p /tmp/install_setup @@ -71,4 +71,3 @@ jobs: - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 - diff --git a/.github/workflows/ferretdb_go_tests.yml b/.github/workflows/ferretdb_go_tests.yml new file mode 100644 index 000000000..8a36fd108 --- /dev/null +++ b/.github/workflows/ferretdb_go_tests.yml @@ -0,0 +1,59 @@ +--- +name: Go +on: + pull_request: + types: + - unlabeled # if GitHub Actions stuck, add and remove "not ready" label to force rebuild + - opened + - reopened + - synchronize + push: + branches: + - ferretdb + tags: + - "*" + schedule: + - cron: "12 0 * * *" + +env: + GOPATH: /home/runner/go + GOCACHE: /home/runner/go/cache + GOLANGCI_LINT_CACHE: /home/runner/go/cache/lint + GOMODCACHE: /home/runner/go/mod + GOPROXY: https://proxy.golang.org + GOTOOLCHAIN: local + +jobs: + test: + name: Test + runs-on: ubuntu-24.04 + timeout-minutes: 15 + + # Do not run this job in parallel for any PR change or branch push. + concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }} + cancel-in-progress: true + + if: github.event_name != 'pull_request' || !contains(github.event.pull_request.labels.*.name, 'not ready') + + steps: + # TODO https://github.com/FerretDB/github-actions/issues/211 + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Go + uses: FerretDB/github-actions/setup-go@main + + - name: Run tests + run: | + cd ferretdb_packaging + go mod tidy + go mod verify + go test ./... + + - name: Check dirty + if: always() + run: | + git status --untracked-files --ignored + git status + git diff --exit-code diff --git a/.github/workflows/ferretdb_packages.yml b/.github/workflows/ferretdb_packages.yml new file mode 100644 index 000000000..0c696994e --- /dev/null +++ b/.github/workflows/ferretdb_packages.yml @@ -0,0 +1,266 @@ +--- +# This and other workflows that use `pull_request_target` event are dangerous +# and should be handled with a lot of care to avoid security problems. +# We use this event to give pull requests access to secrets with permissions to login into Docker registries. +# But rogue PR authors could try to steal our secrets. +# We prevent that with the following: +# +# * We require approval for PRs from first-time contributors. That's a built-in feature for all actions. +# * For workflows that checkout source code, +# we require the `trust` label to be assigned to PRs by FerretDB maintainers after reviewing changes. +# Only a few trusted people have permission to do that. +# * Thanks to the way `pull_request_target` trigger works, +# PR changes in the workflow itself are not run until they are merged. +# * We use short-lived automatic `GITHUB_TOKEN`s instead of a long-living personal access tokens (PAT) where possible. +# * Both `GITHUB_TOKEN`s and PATs have minimal permissions. +# * We publish Docker images from PRs as separate packages that should not be run by users. +# * We limit what third-party actions can be used. +# +# Relevant GitHub documentation is a bit scattered. The first article gives a good overview: +# * https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ +# * https://docs.github.com/en/actions/security-guides/automatic-token-authentication +# * https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions + +name: Packages +on: + pull_request_target: + types: + - unlabeled # if GitHub Actions stuck, add and remove "not ready" label to force rebuild + - opened + - reopened + - synchronize + push: + branches: + - ferretdb + tags: + - "*" + schedule: + - cron: "10 8 * * 1" + +env: + GOPATH: /home/runner/go + GOCACHE: /home/runner/go/cache + GOLANGCI_LINT_CACHE: /home/runner/go/cache/lint + GOMODCACHE: /home/runner/go/mod + GOPROXY: https://proxy.golang.org + GOTOOLCHAIN: local + +# Do not run this workflow in parallel for any PR change or branch/tag push +# to save some resources. +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }} + cancel-in-progress: false + +jobs: + deb: + name: Build .debs (${{ matrix.os }}, Pg${{ matrix.pg }}) + runs-on: ubuntu-24.04 + timeout-minutes: 40 + + if: > + github.event_name != 'pull_request_target' || + ( + contains(github.event.pull_request.labels.*.name, 'trust') && + !contains(github.event.pull_request.labels.*.name, 'not ready') && + contains(github.event.pull_request.labels.*.name, 'packages') + ) + + permissions: {} + + strategy: + fail-fast: false + matrix: + os: [deb11, deb12, ubuntu22.04, ubuntu24.04] + pg: [15, 16, 17] + + steps: + # TODO https://github.com/FerretDB/github-actions/issues/211 + - name: Checkout code + if: github.event_name != 'pull_request_target' + uses: actions/checkout@v4 + with: + fetch-depth: 0 # for `generate_extension_version.sh` to work + + # TODO https://github.com/FerretDB/github-actions/issues/211 + - name: Checkout pull request code + if: github.event_name == 'pull_request_target' + uses: actions/checkout@v4 + with: + fetch-depth: 0 # for `generate_extension_version.sh` to work + ref: ${{ github.event.pull_request.head.sha }} + + - name: Fetch annotated tags + run: | + git fetch --tags --force + git status + + - name: Name branch + if: github.event_name == 'pull_request_target' + env: + BRANCH: ${{ github.head_ref }} # see https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable + run: git checkout -b $BRANCH + + - name: Setup Go + uses: FerretDB/github-actions/setup-go@main + + - name: Define version + id: version + run: | + cd ferretdb_packaging + go mod tidy + go mod verify + go run ./defineversion -control-file ../pg_documentdb/documentdb.control -pg-version ${{ matrix.pg }} -debian-only + + - name: Build ${{ steps.version.outputs.debian_version }} + if: steps.version.outputs.debian_version != '' + run: ./ferretdb_packaging/build_packages.sh --os ${{ matrix.os }} --pg ${{ matrix.pg }} --version ${{ steps.version.outputs.debian_version }} --test-clean-install + + - name: Upload .deb packages + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.os }}-${{ matrix.pg }}-${{ steps.version.outputs.debian_version }} + path: packaging/*.deb + retention-days: 1 + if-no-files-found: error + compression-level: 0 + overwrite: false + + - name: Check dirty + run: | + git status + git diff --exit-code + + docker: + name: Build Docker (Pg${{ matrix.pg }}) + runs-on: ubuntu-24.04 + timeout-minutes: 40 + + needs: deb + + if: > + github.event_name != 'pull_request_target' || + ( + contains(github.event.pull_request.labels.*.name, 'trust') && + !contains(github.event.pull_request.labels.*.name, 'not ready') && + contains(github.event.pull_request.labels.*.name, 'packages') + ) + + permissions: + packages: write + + strategy: + fail-fast: false + matrix: + pg: [15, 16, 17] + + steps: + # TODO https://github.com/FerretDB/github-actions/issues/211 + - name: Checkout code + if: github.event_name != 'pull_request_target' + uses: actions/checkout@v4 + with: + fetch-depth: 0 # for `generate_extension_version.sh` to work + + # TODO https://github.com/FerretDB/github-actions/issues/211 + - name: Checkout pull request code + if: github.event_name == 'pull_request_target' + uses: actions/checkout@v4 + with: + fetch-depth: 0 # for `generate_extension_version.sh` to work + ref: ${{ github.event.pull_request.head.sha }} + + - name: Fetch annotated tags + run: | + git fetch --tags --force + git status + + - name: Name branch + if: github.event_name == 'pull_request_target' + env: + BRANCH: ${{ github.head_ref }} # see https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable + run: git checkout -b $BRANCH + + - name: Setup Go + uses: FerretDB/github-actions/setup-go@main + + - name: Define version + id: version + run: | + cd ferretdb_packaging + go mod tidy + go mod verify + go run ./defineversion -control-file ../pg_documentdb/documentdb.control -pg-version ${{ matrix.pg }} + + - name: Download deb12-${{ matrix.pg }}-${{ steps.version.outputs.debian_version }} + uses: actions/download-artifact@v4 + with: + name: deb12-${{ matrix.pg }}-${{ steps.version.outputs.debian_version }} + path: packaging + + - name: Initialize Docker builder + run: make -C ferretdb_packaging docker-init + + - name: Build local development Docker image + if: steps.version.outputs.docker_development_tag_flags != '' + run: > + make -C ferretdb_packaging docker-build + POSTGRES_VERSION=${{ matrix.pg }} + DOCUMENTDB_VERSION=${{ steps.version.outputs.debian_version }} + FILE=development + OUTPUT='type=docker' + TAGS='${{ steps.version.outputs.docker_development_tag_flags }}' + + - name: Build local production Docker image + if: steps.version.outputs.docker_production_tag_flags != '' + run: > + make -C ferretdb_packaging docker-build + POSTGRES_VERSION=${{ matrix.pg }} + DOCUMENTDB_VERSION=${{ steps.version.outputs.debian_version }} + FILE=production + OUTPUT='type=docker' + TAGS='${{ steps.version.outputs.docker_production_tag_flags }}' + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ferretdbbot + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Login to Quay.io + uses: docker/login-action@v3 + with: + registry: quay.io + username: ferretdb+ferretdbbot + password: ${{ secrets.QUAY_TOKEN }} + + - name: Build and push development Docker images + if: steps.version.outputs.docker_development_tag_flags != '' + run: > + make -C ferretdb_packaging docker-build + POSTGRES_VERSION=${{ matrix.pg }} + DOCUMENTDB_VERSION=${{ steps.version.outputs.debian_version }} + FILE=development + OUTPUT='type=image,push=true' + TAGS='${{ steps.version.outputs.docker_development_tag_flags }}' + + - name: Build and push production Docker images + if: steps.version.outputs.docker_production_tag_flags != '' + run: > + make -C ferretdb_packaging docker-build + POSTGRES_VERSION=${{ matrix.pg }} + DOCUMENTDB_VERSION=${{ steps.version.outputs.debian_version }} + FILE=production + OUTPUT='type=image,push=true' + TAGS='${{ steps.version.outputs.docker_production_tag_flags }}' + + - name: Check dirty + run: | + git status + git diff --exit-code diff --git a/.github/workflows/regress_tests.yml b/.github/workflows/regress_tests.yml index ecb858942..ba6a5be42 100644 --- a/.github/workflows/regress_tests.yml +++ b/.github/workflows/regress_tests.yml @@ -9,6 +9,7 @@ on: push: branches: - 'main' + - 'ferretdb' paths-ignore: - 'docs/**' - '.devcontainer/**' diff --git a/.gitignore b/.gitignore index 2013d0adc..465a2e6ad 100755 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,9 @@ *.idb *.pdb +# FerretDB packaging +*.deb + # Kernel Module Compile Results *.mod* *.cmd diff --git a/CHANGELOG.md b/CHANGELOG.md index fb16e7494..daf10ec6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,37 @@ * Support collation with `$documents` and `$replaceWith` stage of the aggregation pipeline *[Feature]* * Push pg_documentdb_gw for documentdb connections *[Feature]* +### DocumentDB v0.102.0-ferretdb-2.1.0 (April 2, 2025) ### + +> [!CAUTION] +> Please note that due to incompatibilities in our previous releases, they can't be updated in place, +> even with a manual `ALTER EXTENSION UPDATE` query or other means. +> A new clean installation into an empty data directory/volume is required. +> All data should be backed up with `mongodump`/`mongoexport` before +> and restored with `mongorestore`/`mongoimport` after. +> +> We expect future updates to be much smoother. + +This version works best with the upcoming FerretDB v2.1.0. + +Debian and Ubuntu `.deb` packages are provided [on the release page](https://github.com/FerretDB/documentdb/releases/tag/v0.102.0-ferretdb-2.1.0). +See installation instructions [in our documentation](https://docs.ferretdb.io/installation/documentdb/deb/). + +Docker images are available [in the registry](https://github.com/FerretDB/documentdb/pkgs/container/postgres-documentdb). +See installation instructions [in our documentation](https://docs.ferretdb.io/installation/documentdb/docker/). +We always recommend specifying the full image tag (e.g., `17-0.102.0-ferretdb-2.1.0`, not just `17` or `17-0.102.0`) to avoid unexpected updates. + +### DocumentDB v0.102.0-ferretdb-2.0.0 (GA) (March 5, 2025) ### + +This version works best with [FerretDB v2.0.0 (GA)](https://github.com/FerretDB/FerretDB/releases/tag/v2.0.0). + +Debian and Ubuntu `.deb` packages are provided [on the release page](https://github.com/FerretDB/documentdb/releases/tag/v0.102.0-ferretdb-2.0.0). +See installation instructions [in our documentation](https://docs.ferretdb.io/installation/documentdb/deb/). + +Docker images are available [in the registry](https://github.com/FerretDB/documentdb/pkgs/container/postgres-documentdb). +See installation instructions [in our documentation](https://docs.ferretdb.io/installation/documentdb/docker/). +We always recommend specifying the full image tag (e.g., `17-0.102.0-ferretdb-2.0.0`, not just `17` or `17-0.102.0`) to avoid unexpected updates. + ### documentdb v0.102-0 (March 26, 2025) ### * Support index pushdown for vector search queries *[Bugfix]* * Support exact search for vector search queries *[Feature]* diff --git a/CODEOWNERS b/CODEOWNERS index 6c6098c52..9a9db1207 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -8,4 +8,6 @@ Make* @microsoft/documentdb-engine-reviewers /internal/ @microsoft/documentdb-engine-reviewers /pg_documentdb/ @microsoft/documentdb-engine-reviewers -/pg_documentdb_core/ @microsoft/documentdb-engine-reviewers \ No newline at end of file +/pg_documentdb_core/ @microsoft/documentdb-engine-reviewers + +* @AlekSi diff --git a/ferretdb_packaging/.gitignore b/ferretdb_packaging/.gitignore new file mode 100644 index 000000000..353ce6cb8 --- /dev/null +++ b/ferretdb_packaging/.gitignore @@ -0,0 +1,2 @@ +# FerretDB packaging +!*go.mod diff --git a/ferretdb_packaging/10-preload.sh b/ferretdb_packaging/10-preload.sh new file mode 100755 index 000000000..7e1e9eba6 --- /dev/null +++ b/ferretdb_packaging/10-preload.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -e + +# https://github.com/microsoft/documentdb/tree/main/pg_documentdb/src/configs + +cat <> $PGDATA/postgresql.conf +shared_preload_libraries = 'pg_cron,pg_documentdb_core,pg_documentdb' +cron.database_name = 'postgres' + +documentdb.enableLetAndCollationForQueryMatch = true +documentdb.enableNowSystemVariable = true +documentdb.enableSortbyIdPushDownToPrimaryKey = true + +documentdb.enableSchemaValidation = true +documentdb.enableBypassDocumentValidation = true + +documentdb.enableUserCrud = true +documentdb.maxUserLimit = 100 +EOT + +source /usr/local/bin/docker-entrypoint.sh + +# restarting is needed to create extension +docker_temp_server_stop +docker_temp_server_start "$@" diff --git a/ferretdb_packaging/20-install.sql b/ferretdb_packaging/20-install.sql new file mode 100644 index 000000000..34c7b1140 --- /dev/null +++ b/ferretdb_packaging/20-install.sql @@ -0,0 +1 @@ +CREATE EXTENSION documentdb CASCADE; diff --git a/ferretdb_packaging/90-install-development.sql b/ferretdb_packaging/90-install-development.sql new file mode 100644 index 000000000..070b769a5 --- /dev/null +++ b/ferretdb_packaging/90-install-development.sql @@ -0,0 +1 @@ +CREATE EXTENSION pgtap; diff --git a/ferretdb_packaging/Makefile b/ferretdb_packaging/Makefile new file mode 100644 index 000000000..a304d0940 --- /dev/null +++ b/ferretdb_packaging/Makefile @@ -0,0 +1,37 @@ +.PHONY: docker-init docker-build docker-cleanup + +docker-init: + docker buildx create \ + --driver=docker-container \ + --name=documentdb \ + --bootstrap=true \ + --use=false \ + --config=./buildkitd.toml \ + --driver-opt network=host \ + --driver-opt env.JAEGER_TRACE=127.0.0.1:6831 \ + --driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=-1 \ + --driver-opt env.BUILDKIT_STEP_LOG_MAX_SPEED=-1 \ + || true + docker buildx ls + +docker-build: + test -n "$(POSTGRES_VERSION)" || (echo "POSTGRES_VERSION not set" && false) + test -n "$(DOCUMENTDB_VERSION)" || (echo "DOCUMENTDB_VERSION not set" && false) + test -n "$(FILE)" || (echo "FILE not set" && false) + test -n "$(OUTPUT)" || (echo "OUTPUT not set" && false) + test -n "$(TAGS)" || (echo "TAGS not set" && false) + docker buildx build --builder=documentdb \ + --file=$(FILE).Dockerfile \ + --build-arg='POSTGRES_VERSION=$(POSTGRES_VERSION)' \ + --build-arg='DOCUMENTDB_VERSION=$(DOCUMENTDB_VERSION)' \ + --platform=linux/amd64 \ + --output='$(OUTPUT)' \ + $(TAGS) \ + .. + +docker-cleanup: + docker system df + docker buildx --builder=documentdb du || true + docker buildx --builder=documentdb rm --force || true + docker system prune --force + docker system df diff --git a/ferretdb_packaging/buildkitd.toml b/ferretdb_packaging/buildkitd.toml new file mode 100644 index 000000000..1add01ddb --- /dev/null +++ b/ferretdb_packaging/buildkitd.toml @@ -0,0 +1,5 @@ +[worker.oci] + gc = false + +[worker.containerd] + gc = false diff --git a/ferretdb_packaging/defineversion/debian.go b/ferretdb_packaging/defineversion/debian.go new file mode 100644 index 000000000..6cb0191f8 --- /dev/null +++ b/ferretdb_packaging/defineversion/debian.go @@ -0,0 +1,35 @@ +package main + +import ( + "fmt" + "os" + "regexp" +) + +// controlDefaultVer matches major, minor and "patch" from `default_version` field in control file, +// see pg_documentdb_core/documentdb_core.control. +var controlDefaultVer = regexp.MustCompile(`(?m)^default_version = '(?P[0-9]+)\.(?P[0-9]+)-(?P[0-9]+)'$`) + +// disallowedDebian matches disallowed characters of Debian `upstream_version` when used without `debian_revision`. +// See https://www.debian.org/doc/debian-policy/ch-controlfields.html#version. +var disallowedDebian = regexp.MustCompile(`[^A-Za-z0-9\.+~]`) + +// getControlDefaultVersion returns the default_version field from the control file +// in SemVer format (0.103-0 -> 0.103.0). +func getControlDefaultVersion(f string) (string, error) { + b, err := os.ReadFile(f) + if err != nil { + return "", err + } + + match := controlDefaultVer.FindSubmatch(b) + if match == nil || len(match) != controlDefaultVer.NumSubexp()+1 { + return "", fmt.Errorf("control file did not find default_version: %s", f) + } + + major := match[controlDefaultVer.SubexpIndex("major")] + minor := match[controlDefaultVer.SubexpIndex("minor")] + patch := match[controlDefaultVer.SubexpIndex("patch")] + + return fmt.Sprintf("%s.%s.%s", major, minor, patch), nil +} diff --git a/ferretdb_packaging/defineversion/debian_test.go b/ferretdb_packaging/defineversion/debian_test.go new file mode 100644 index 000000000..c98e6f1bc --- /dev/null +++ b/ferretdb_packaging/defineversion/debian_test.go @@ -0,0 +1,30 @@ +package main + +import ( + "io" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestReadControlDefaultVersion(t *testing.T) { + controlF, err := os.CreateTemp(t.TempDir(), "test.control") + require.NoError(t, err) + + defer controlF.Close() //nolint:errcheck // temporary file for testing + + buf := `comment = 'API surface for DocumentDB for PostgreSQL' +default_version = '0.103-0' +module_pathname = '$libdir/pg_documentdb' +relocatable = false +superuser = true +requires = 'documentdb_core, pg_cron, tsm_system_rows, vector, postgis, rum'` + _, err = io.WriteString(controlF, buf) + require.NoError(t, err) + + controlDefaultVersion, err := getControlDefaultVersion(controlF.Name()) + require.NoError(t, err) + + require.Equal(t, "0.103.0", controlDefaultVersion) +} diff --git a/ferretdb_packaging/defineversion/docker.go b/ferretdb_packaging/defineversion/docker.go new file mode 100644 index 000000000..ebe2c47e8 --- /dev/null +++ b/ferretdb_packaging/defineversion/docker.go @@ -0,0 +1,21 @@ +package main + +import ( + "fmt" + "strings" +) + +// dockerImageURL returns HTML page URL for the given image name and tag. +func dockerImageURL(name string) string { + switch { + case strings.HasPrefix(name, "ghcr.io/"): + return fmt.Sprintf("https://%s", name) + case strings.HasPrefix(name, "quay.io/"): + return fmt.Sprintf("https://%s", name) + } + + name, _, _ = strings.Cut(name, ":") + + // there is no easy way to get Docker Hub URL for the given tag + return fmt.Sprintf("https://hub.docker.com/r/%s/tags", name) +} diff --git a/ferretdb_packaging/defineversion/docker_test.go b/ferretdb_packaging/defineversion/docker_test.go new file mode 100644 index 000000000..9911ba38b --- /dev/null +++ b/ferretdb_packaging/defineversion/docker_test.go @@ -0,0 +1,26 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestImageURL(t *testing.T) { + // expected URLs should work + assert.Equal( + t, + "https://ghcr.io/ferretdb/postgres-documentdb-dev:pr-docker-tag", + dockerImageURL("ghcr.io/ferretdb/postgres-documentdb-dev:pr-docker-tag"), + ) + assert.Equal( + t, + "https://quay.io/ferretdb/postgres-documentdb-dev:pr-docker-tag", + dockerImageURL("quay.io/ferretdb/postgres-documentdb-dev:pr-docker-tag"), + ) + assert.Equal( + t, + "https://hub.docker.com/r/ferretdb/postgres-documentdb-dev/tags", + dockerImageURL("ferretdb/postgres-documentdb-dev:pr-docker-tag"), + ) +} diff --git a/ferretdb_packaging/defineversion/main.go b/ferretdb_packaging/defineversion/main.go new file mode 100644 index 000000000..fd7a8b4e4 --- /dev/null +++ b/ferretdb_packaging/defineversion/main.go @@ -0,0 +1,328 @@ +// Package main defines version numbers for DocumentDB. +package main + +import ( + "flag" + "fmt" + "os" + "regexp" + "slices" + "strconv" + "strings" + "text/tabwriter" + + "github.com/sethvargo/go-githubactions" +) + +// semVerTag is a https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string, +// but with a leading `v`. +var semVerTag = regexp.MustCompile(`^v(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`) + +// versions represents Docker image names and tags, and Debian package version. +type versions struct { + dockerDevelopmentImages []string + dockerProductionImages []string + debian string +} + +// parseGitTag parses git tag in specific format and returns SemVer components. +// +// Expected format is v0.103.0-ferretdb-2.2.0-beta.1, +// where v0.103.0 is a DocumentDB version (0.103-0 -> 0.103.0), +// and ferretdb-2.2.0-beta.1 is a compatible FerretDB version. +func parseGitTag(tag string) (major, minor, patch int, prerelease string, err error) { + match := semVerTag.FindStringSubmatch(tag) + if match == nil || len(match) != semVerTag.NumSubexp()+1 { + err = fmt.Errorf("unexpected git tag format %q", tag) + return + } + + if major, err = strconv.Atoi(match[semVerTag.SubexpIndex("major")]); err != nil { + return + } + if minor, err = strconv.Atoi(match[semVerTag.SubexpIndex("minor")]); err != nil { + return + } + if patch, err = strconv.Atoi(match[semVerTag.SubexpIndex("patch")]); err != nil { + return + } + prerelease = match[semVerTag.SubexpIndex("prerelease")] + buildmetadata := match[semVerTag.SubexpIndex("buildmetadata")] + + if !strings.HasPrefix(prerelease, "ferretdb-") { + err = fmt.Errorf("prerelease %q should start with 'ferretdb-'", prerelease) + return + } + + if buildmetadata != "" { + err = fmt.Errorf("buildmetadata %q is present", buildmetadata) + return + } + + return +} + +// debugEnv logs all environment variables that start with `GITHUB_` or `INPUT_` +// in debug level. +func debugEnv(action *githubactions.Action) { + res := make([]string, 0, 30) + + for _, l := range os.Environ() { + if strings.HasPrefix(l, "GITHUB_") || strings.HasPrefix(l, "INPUT_") { + res = append(res, l) + } + } + + slices.Sort(res) + + action.Debugf("Dumping environment variables:") + + for _, l := range res { + action.Debugf("\t%s", l) + } +} + +// defineVersion extracts Docker image names and tags, and Debian package version using the environment variables defined by GitHub Actions. +// +// The Debian package version is based on `default_version` in the control file. +// See https://www.debian.org/doc/debian-policy/ch-controlfields.html#version. +// We use `upstream_version` only. +// For that reason, we can't use `-`, so we replace it with `~`. +func defineVersion(controlDefaultVersion, pgVersion string, getenv githubactions.GetenvFunc) (*versions, error) { + repo := getenv("GITHUB_REPOSITORY") + + // to support GitHub forks + parts := strings.Split(strings.ToLower(repo), "/") + if len(parts) != 2 { + return nil, fmt.Errorf("failed to split %q into owner and name", repo) + } + owner := parts[0] + repo = parts[1] + + var res *versions + var err error + + switch event := getenv("GITHUB_EVENT_NAME"); event { + case "pull_request", "pull_request_target": + branch := strings.ToLower(getenv("GITHUB_HEAD_REF")) + res = defineVersionForPR(controlDefaultVersion, pgVersion, owner, repo, branch) + + case "push", "schedule", "workflow_run": + refName := strings.ToLower(getenv("GITHUB_REF_NAME")) + + switch refType := strings.ToLower(getenv("GITHUB_REF_TYPE")); refType { + case "branch": + res, err = defineVersionForBranch(controlDefaultVersion, pgVersion, owner, repo, refName) + + case "tag": + res, err = defineVersionForTag(controlDefaultVersion, pgVersion, owner, repo, refName) + + default: + err = fmt.Errorf("unhandled ref type %q for event %q", refType, event) + } + + default: + err = fmt.Errorf("unhandled event type %q", event) + } + + if err != nil { + return nil, err + } + + if res == nil { + return nil, fmt.Errorf("both res and err are nil") + } + + slices.Sort(res.dockerDevelopmentImages) + slices.Sort(res.dockerProductionImages) + + return res, nil +} + +// defineVersionForPR defines Docker image names and tags, and Debian package version for PR. +// See [defineVersion]. +func defineVersionForPR(controlDefaultVersion, pgVersion, owner, repo, branch string) *versions { + // for branches like "dependabot/submodules/XXX" + parts := strings.Split(branch, "/") + branch = parts[len(parts)-1] + + res := &versions{ + dockerDevelopmentImages: []string{ + fmt.Sprintf("ghcr.io/%s/postgres-%s-dev:%s-pr-%s", owner, repo, pgVersion, branch), + }, + debian: disallowedDebian.ReplaceAllString(fmt.Sprintf("%s-pr-%s", controlDefaultVersion, branch), "~"), + } + + // PRs are only for testing; no Quay.io and Docker Hub repos + + return res +} + +// defineVersionForBranch defines Docker image names and tags, and Debian package version for branch. +// See [defineVersion]. +func defineVersionForBranch(controlDefaultVersion, pgVersion, owner, repo, branch string) (*versions, error) { + if branch != "ferretdb" { + return nil, fmt.Errorf("unhandled branch %q", branch) + } + + res := &versions{ + dockerDevelopmentImages: []string{ + fmt.Sprintf("ghcr.io/%s/postgres-%s-dev:%s-ferretdb", owner, repo, pgVersion), + }, + debian: fmt.Sprintf("%s~ferretdb", controlDefaultVersion), + } + + // forks don't have Quay.io and Docker Hub orgs + if owner != "ferretdb" { + return res, nil + } + + // we don't have Quay.io and Docker Hub repos for other GitHub repos + if repo != "documentdb" { + return res, nil + } + + res.dockerDevelopmentImages = append(res.dockerDevelopmentImages, fmt.Sprintf("quay.io/ferretdb/postgres-documentdb-dev:%s-ferretdb", pgVersion)) + res.dockerDevelopmentImages = append(res.dockerDevelopmentImages, fmt.Sprintf("ferretdb/postgres-documentdb-dev:%s-ferretdb", pgVersion)) + + return res, nil +} + +// defineVersionForTag defines Docker image names and tags, and Debian package version for tag. +// See [defineVersion]. +func defineVersionForTag(controlDefaultVersion, pgVersion, owner, repo, tag string) (*versions, error) { + major, minor, patch, prerelease, err := parseGitTag(tag) + if err != nil { + return nil, err + } + + tagVersion := fmt.Sprintf("%d.%d.%d", major, minor, patch) + if tagVersion != controlDefaultVersion { + return nil, fmt.Errorf("git tag version %q does not match the control file default version %q", tagVersion, controlDefaultVersion) + } + + tags := []string{ + fmt.Sprintf("%s-%s-%s", pgVersion, tagVersion, prerelease), + fmt.Sprintf("%s-%s", pgVersion, tagVersion), + fmt.Sprintf("%s", pgVersion), + } + + if pgVersion == "17" { + tags = append(tags, "latest") + } + + res := versions{ + debian: disallowedDebian.ReplaceAllString(fmt.Sprintf("%s-%s", tagVersion, prerelease), "~"), + } + + for _, t := range tags { + res.dockerDevelopmentImages = append(res.dockerDevelopmentImages, fmt.Sprintf("ghcr.io/%s/postgres-%s-dev:%s", owner, repo, t)) + res.dockerProductionImages = append(res.dockerProductionImages, fmt.Sprintf("ghcr.io/%s/postgres-%s:%s", owner, repo, t)) + } + + // forks don't have Quay.io and Docker Hub orgs + if owner != "ferretdb" { + return &res, nil + } + + // we don't have Quay.io and Docker Hub repos for other GitHub repos + if repo != "documentdb" { + return &res, nil + } + + for _, t := range tags { + res.dockerDevelopmentImages = append(res.dockerDevelopmentImages, fmt.Sprintf("quay.io/ferretdb/postgres-documentdb-dev:%s", t)) + res.dockerProductionImages = append(res.dockerProductionImages, fmt.Sprintf("quay.io/ferretdb/postgres-documentdb:%s", t)) + + res.dockerDevelopmentImages = append(res.dockerDevelopmentImages, fmt.Sprintf("ferretdb/postgres-documentdb-dev:%s", t)) + res.dockerProductionImages = append(res.dockerProductionImages, fmt.Sprintf("ferretdb/postgres-documentdb:%s", t)) + } + + return &res, nil +} + +// setSummary sets action summary. +func setSummary(action *githubactions.Action, version *versions) { + var buf strings.Builder + + fmt.Fprintf(&buf, "Debian package version (`upstream_version` only): `%s`\n\n", version.debian) + + w := tabwriter.NewWriter(&buf, 1, 1, 1, ' ', tabwriter.Debug) + fmt.Fprintf(w, "\tType\tDocker image\t\n") + fmt.Fprintf(w, "\t----\t------------\t\n") + + for _, image := range version.dockerDevelopmentImages { + u := dockerImageURL(image) + _, _ = fmt.Fprintf(w, "\tDevelopment\t[`%s`](%s)\t\n", image, u) + } + + for _, image := range version.dockerProductionImages { + u := dockerImageURL(image) + _, _ = fmt.Fprintf(w, "\tProduction\t[`%s`](%s)\t\n", image, u) + } + + _ = w.Flush() + + action.AddStepSummary(buf.String()) + action.Infof("%s", buf.String()) +} + +func main() { + controlFileF := flag.String("control-file", "../pg_documentdb/documentdb.control", "pg_documentdb/documentdb.control file path") + pgVersionF := flag.String("pg-version", "17", "Major PostgreSQL version") + debianOnlyF := flag.Bool("debian-only", false, "Only set output for Debian package version") + + flag.Parse() + + action := githubactions.New() + + debugEnv(action) + + if *controlFileF == "" { + action.Fatalf("%s", "-control-file flag is empty.") + } + + switch *pgVersionF { + case "15", "16", "17": + // nothing + default: + action.Fatalf("%s", fmt.Sprintf("Invalid PostgreSQL version %q.", *pgVersionF)) + } + + controlDefaultVersion, err := getControlDefaultVersion(*controlFileF) + if err != nil { + action.Fatalf("%s", err) + } + + res, err := defineVersion(controlDefaultVersion, *pgVersionF, action.Getenv) + if err != nil { + action.Fatalf("%s", err) + } + + action.SetOutput("debian_version", res.debian) + + if *debianOnlyF { + // Only 3 summaries are shown in the GitHub Actions UI by default, + // and Docker summaries are more important (and include Debian version anyway). + output := fmt.Sprintf("Debian package version (`upstream_version` only): `%s`", res.debian) + action.Infof("%s", output) + return + } + + setSummary(action, res) + + action.SetOutput("docker_development_images", strings.Join(res.dockerDevelopmentImages, ",")) + action.SetOutput("docker_production_images", strings.Join(res.dockerProductionImages, ",")) + + developmentTagFlags := make([]string, len(res.dockerDevelopmentImages)) + for i, image := range res.dockerDevelopmentImages { + developmentTagFlags[i] = fmt.Sprintf("--tag %s", image) + } + action.SetOutput("docker_development_tag_flags", strings.Join(developmentTagFlags, " ")) + + productionTagFlags := make([]string, len(res.dockerProductionImages)) + for i, image := range res.dockerProductionImages { + productionTagFlags[i] = fmt.Sprintf("--tag %s", image) + } + action.SetOutput("docker_production_tag_flags", strings.Join(productionTagFlags, " ")) +} diff --git a/ferretdb_packaging/defineversion/main_test.go b/ferretdb_packaging/defineversion/main_test.go new file mode 100644 index 000000000..6dba699af --- /dev/null +++ b/ferretdb_packaging/defineversion/main_test.go @@ -0,0 +1,442 @@ +package main + +import ( + "bytes" + "fmt" + "io" + "os" + "strings" + "testing" + + "github.com/sethvargo/go-githubactions" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// getEnvFunc implements [os.Getenv] for testing. +func getEnvFunc(t *testing.T, env map[string]string) func(string) string { + t.Helper() + + return func(key string) string { + val, ok := env[key] + require.True(t, ok, "missing key %q", key) + + return val + } +} + +func TestParseGitTag(t *testing.T) { + tests := map[string]struct { + major int + minor int + patch int + prerelease string + err string + }{ + "v0.103.0-ferretdb-2.2.0-beta.1": { + major: 0, + minor: 103, + patch: 0, + prerelease: "ferretdb-2.2.0-beta.1", + }, + "0.103.0-ferretdb-2.2.0-beta.1": { + err: `unexpected git tag format "0.103.0-ferretdb-2.2.0-beta.1"`, + }, + "v0.103.0-ferretdb": { + err: `prerelease "ferretdb" should start with 'ferretdb-'`, + }, + "v0.103.0": { + err: `prerelease "" should start with 'ferretdb-'`, + }, + } + + for tag, tc := range tests { + t.Run(tag, func(t *testing.T) { + major, minor, patch, prerelease, err := parseGitTag(tag) + if tc.err != "" { + require.EqualError(t, err, tc.err) + return + } + + require.NoError(t, err) + + assert.Equal(t, tc.major, major) + assert.Equal(t, tc.minor, minor) + assert.Equal(t, tc.patch, patch) + assert.Equal(t, tc.prerelease, prerelease) + }) + } +} + +func TestDefineVersion(t *testing.T) { + const pgVersion = "17" + + for name, tc := range map[string]struct { + env map[string]string + controlDefaultVersion string + expected *versions + expectedErr error + }{ + "pull_request": { + env: map[string]string{ + "GITHUB_BASE_REF": "ferretdb", + "GITHUB_EVENT_NAME": "pull_request", + "GITHUB_HEAD_REF": "define-version", + "GITHUB_REF_NAME": "1/merge", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "FerretDB/documentdb", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ghcr.io/ferretdb/postgres-documentdb-dev:17-pr-define-version", + }, + debian: "0.103.0~pr~define~version", + }, + }, + "pull_request-other": { + env: map[string]string{ + "GITHUB_BASE_REF": "ferretdb", + "GITHUB_EVENT_NAME": "pull_request", + "GITHUB_HEAD_REF": "define-version", + "GITHUB_REF_NAME": "1/merge", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "OtherOrg/OtherRepo", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ghcr.io/otherorg/postgres-otherrepo-dev:17-pr-define-version", + }, + debian: "0.103.0~pr~define~version", + }, + }, + + "pull_request_target": { + env: map[string]string{ + "GITHUB_BASE_REF": "ferretdb", + "GITHUB_EVENT_NAME": "pull_request_target", + "GITHUB_HEAD_REF": "define-version", + "GITHUB_REF_NAME": "ferretdb", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "FerretDB/documentdb", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ghcr.io/ferretdb/postgres-documentdb-dev:17-pr-define-version", + }, + debian: "0.103.0~pr~define~version", + }, + }, + "pull_request_target-other": { + env: map[string]string{ + "GITHUB_BASE_REF": "ferretdb", + "GITHUB_EVENT_NAME": "pull_request_target", + "GITHUB_HEAD_REF": "define-version", + "GITHUB_REF_NAME": "ferretdb", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "OtherOrg/OtherRepo", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ghcr.io/otherorg/postgres-otherrepo-dev:17-pr-define-version", + }, + debian: "0.103.0~pr~define~version", + }, + }, + + "push/ferretdb": { + env: map[string]string{ + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "push", + "GITHUB_HEAD_REF": "", + "GITHUB_REF_NAME": "ferretdb", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "FerretDB/documentdb", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ferretdb/postgres-documentdb-dev:17-ferretdb", + "ghcr.io/ferretdb/postgres-documentdb-dev:17-ferretdb", + "quay.io/ferretdb/postgres-documentdb-dev:17-ferretdb", + }, + debian: "0.103.0~ferretdb", + }, + }, + "push/ferretdb-other": { + env: map[string]string{ + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "push", + "GITHUB_HEAD_REF": "", + "GITHUB_REF_NAME": "ferretdb", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "OtherOrg/OtherRepo", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ghcr.io/otherorg/postgres-otherrepo-dev:17-ferretdb", + }, + debian: "0.103.0~ferretdb", + }, + }, + + "push/main": { + env: map[string]string{ + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "push", + "GITHUB_HEAD_REF": "", + "GITHUB_REF_NAME": "main", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "FerretDB/documentdb", + }, + controlDefaultVersion: "0.103.0", + expectedErr: fmt.Errorf(`unhandled branch "main"`), + }, + "push/main-other": { + env: map[string]string{ + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "push", + "GITHUB_HEAD_REF": "", + "GITHUB_REF_NAME": "main", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "OtherOrg/OtherRepo", + }, + controlDefaultVersion: "0.103.0", + expectedErr: fmt.Errorf(`unhandled branch "main"`), + }, + + "push/tag/release": { + env: map[string]string{ + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "push", + "GITHUB_HEAD_REF": "", + "GITHUB_REF_NAME": "v0.103.0-ferretdb-2.2.0-beta.1", + "GITHUB_REF_TYPE": "tag", + "GITHUB_REPOSITORY": "FerretDB/documentdb", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ferretdb/postgres-documentdb-dev:17", + "ferretdb/postgres-documentdb-dev:17-0.103.0", + "ferretdb/postgres-documentdb-dev:17-0.103.0-ferretdb-2.2.0-beta.1", + "ferretdb/postgres-documentdb-dev:latest", + "ghcr.io/ferretdb/postgres-documentdb-dev:17", + "ghcr.io/ferretdb/postgres-documentdb-dev:17-0.103.0", + "ghcr.io/ferretdb/postgres-documentdb-dev:17-0.103.0-ferretdb-2.2.0-beta.1", + "ghcr.io/ferretdb/postgres-documentdb-dev:latest", + "quay.io/ferretdb/postgres-documentdb-dev:17", + "quay.io/ferretdb/postgres-documentdb-dev:17-0.103.0", + "quay.io/ferretdb/postgres-documentdb-dev:17-0.103.0-ferretdb-2.2.0-beta.1", + "quay.io/ferretdb/postgres-documentdb-dev:latest", + }, + dockerProductionImages: []string{ + "ferretdb/postgres-documentdb:17", + "ferretdb/postgres-documentdb:17-0.103.0", + "ferretdb/postgres-documentdb:17-0.103.0-ferretdb-2.2.0-beta.1", + "ferretdb/postgres-documentdb:latest", + "ghcr.io/ferretdb/postgres-documentdb:17", + "ghcr.io/ferretdb/postgres-documentdb:17-0.103.0", + "ghcr.io/ferretdb/postgres-documentdb:17-0.103.0-ferretdb-2.2.0-beta.1", + "ghcr.io/ferretdb/postgres-documentdb:latest", + "quay.io/ferretdb/postgres-documentdb:17", + "quay.io/ferretdb/postgres-documentdb:17-0.103.0", + "quay.io/ferretdb/postgres-documentdb:17-0.103.0-ferretdb-2.2.0-beta.1", + "quay.io/ferretdb/postgres-documentdb:latest", + }, + debian: "0.103.0~ferretdb~2.2.0~beta.1", + }, + }, + "push/tag/release-other": { + env: map[string]string{ + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "push", + "GITHUB_HEAD_REF": "", + "GITHUB_REF_NAME": "v0.103.0-ferretdb-2.2.0-beta.1", + "GITHUB_REF_TYPE": "tag", + "GITHUB_REPOSITORY": "OtherOrg/OtherRepo", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ghcr.io/otherorg/postgres-otherrepo-dev:17", + "ghcr.io/otherorg/postgres-otherrepo-dev:17-0.103.0", + "ghcr.io/otherorg/postgres-otherrepo-dev:17-0.103.0-ferretdb-2.2.0-beta.1", + "ghcr.io/otherorg/postgres-otherrepo-dev:latest", + }, + dockerProductionImages: []string{ + "ghcr.io/otherorg/postgres-otherrepo:17", + "ghcr.io/otherorg/postgres-otherrepo:17-0.103.0", + "ghcr.io/otherorg/postgres-otherrepo:17-0.103.0-ferretdb-2.2.0-beta.1", + "ghcr.io/otherorg/postgres-otherrepo:latest", + }, + debian: "0.103.0~ferretdb~2.2.0~beta.1", + }, + }, + + "push/tag/release-wrong-control-default-version": { + env: map[string]string{ + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "push", + "GITHUB_HEAD_REF": "", + "GITHUB_REF_NAME": "v0.103.0-ferretdb-2.2.0-beta.1", + "GITHUB_REF_TYPE": "tag", + "GITHUB_REPOSITORY": "FerretDB/documentdb", + }, + controlDefaultVersion: "0.104.0", + expectedErr: fmt.Errorf(`git tag version "0.103.0" does not match the control file default version "0.104.0"`), + }, + + "schedule": { + env: map[string]string{ + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "schedule", + "GITHUB_HEAD_REF": "", + "GITHUB_REF_NAME": "ferretdb", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "FerretDB/documentdb", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ferretdb/postgres-documentdb-dev:17-ferretdb", + "ghcr.io/ferretdb/postgres-documentdb-dev:17-ferretdb", + "quay.io/ferretdb/postgres-documentdb-dev:17-ferretdb", + }, + debian: "0.103.0~ferretdb", + }, + }, + "schedule-other": { + env: map[string]string{ + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "schedule", + "GITHUB_HEAD_REF": "", + "GITHUB_REF_NAME": "ferretdb", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "OtherOrg/OtherRepo", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ghcr.io/otherorg/postgres-otherrepo-dev:17-ferretdb", + }, + debian: "0.103.0~ferretdb", + }, + }, + + "workflow_run": { + env: map[string]string{ + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "workflow_run", + "GITHUB_HEAD_REF": "", + "GITHUB_REF_NAME": "ferretdb", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "FerretDB/documentdb", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ferretdb/postgres-documentdb-dev:17-ferretdb", + "ghcr.io/ferretdb/postgres-documentdb-dev:17-ferretdb", + "quay.io/ferretdb/postgres-documentdb-dev:17-ferretdb", + }, + debian: "0.103.0~ferretdb", + }, + }, + "workflow_run-other": { + env: map[string]string{ + "GITHUB_BASE_REF": "", + "GITHUB_EVENT_NAME": "workflow_run", + "GITHUB_HEAD_REF": "", + "GITHUB_REF_NAME": "ferretdb", + "GITHUB_REF_TYPE": "branch", + "GITHUB_REPOSITORY": "OtherOrg/OtherRepo", + }, + controlDefaultVersion: "0.103.0", + expected: &versions{ + dockerDevelopmentImages: []string{ + "ghcr.io/otherorg/postgres-otherrepo-dev:17-ferretdb", + }, + debian: "0.103.0~ferretdb", + }, + }, + } { + t.Run(name, func(t *testing.T) { + docker, err := defineVersion(tc.controlDefaultVersion, pgVersion, getEnvFunc(t, tc.env)) + if tc.expected == nil { + require.Error(t, tc.expectedErr) + require.Equal(t, err, tc.expectedErr) + return + } + + require.NoError(t, tc.expectedErr) + require.NoError(t, err) + + assert.Equal(t, tc.expected, docker) + }) + } +} + +func TestSummary(t *testing.T) { + dir := t.TempDir() + + summaryF, err := os.CreateTemp(dir, "summary") + require.NoError(t, err) + defer summaryF.Close() + + outputF, err := os.CreateTemp(dir, "output") + require.NoError(t, err) + defer outputF.Close() + + var stdout bytes.Buffer + getenv := getEnvFunc(t, map[string]string{ + "GITHUB_STEP_SUMMARY": summaryF.Name(), + "GITHUB_OUTPUT": outputF.Name(), + }) + action := githubactions.New(githubactions.WithGetenv(getenv), githubactions.WithWriter(&stdout)) + + result := &versions{ + dockerDevelopmentImages: []string{ + "ghcr.io/ferretdb/postgres-documentdb-dev:17-0.103.0-ferretdb", + "ghcr.io/ferretdb/postgres-documentdb-dev:latest", + }, + dockerProductionImages: []string{ + "quay.io/ferretdb/postgres-documentdb:latest", + }, + debian: "0.103.0~ferretdb", + } + + setSummary(action, result) + + expectedStdout := strings.ReplaceAll(` +Debian package version ('upstream_version' only): '0.103.0~ferretdb' + + |Type |Docker image | + |---- |------------ | + |Development |['ghcr.io/ferretdb/postgres-documentdb-dev:17-0.103.0-ferretdb'](https://ghcr.io/ferretdb/postgres-documentdb-dev:17-0.103.0-ferretdb) | + |Development |['ghcr.io/ferretdb/postgres-documentdb-dev:latest'](https://ghcr.io/ferretdb/postgres-documentdb-dev:latest) | + |Production |['quay.io/ferretdb/postgres-documentdb:latest'](https://quay.io/ferretdb/postgres-documentdb:latest) | + +`[1:], "'", "`", + ) + assert.Equal(t, expectedStdout, stdout.String(), "stdout does not match") + + expectedSummary := strings.ReplaceAll(` +Debian package version ('upstream_version' only): '0.103.0~ferretdb' + + |Type |Docker image | + |---- |------------ | + |Development |['ghcr.io/ferretdb/postgres-documentdb-dev:17-0.103.0-ferretdb'](https://ghcr.io/ferretdb/postgres-documentdb-dev:17-0.103.0-ferretdb) | + |Development |['ghcr.io/ferretdb/postgres-documentdb-dev:latest'](https://ghcr.io/ferretdb/postgres-documentdb-dev:latest) | + |Production |['quay.io/ferretdb/postgres-documentdb:latest'](https://quay.io/ferretdb/postgres-documentdb:latest) | + +`[1:], "'", "`", + ) + b, err := io.ReadAll(summaryF) + require.NoError(t, err) + assert.Equal(t, expectedSummary, string(b), "summary does not match") +} diff --git a/ferretdb_packaging/development.Dockerfile b/ferretdb_packaging/development.Dockerfile new file mode 100644 index 000000000..7d63aa8c4 --- /dev/null +++ b/ferretdb_packaging/development.Dockerfile @@ -0,0 +1,63 @@ +# syntax=docker/dockerfile:1 + +ARG POSTGRES_VERSION + +FROM postgres:${POSTGRES_VERSION} AS development + +ARG POSTGRES_VERSION +ARG DOCUMENTDB_VERSION + +RUN --mount=type=cache,sharing=locked,target=/var/cache/apt < --pg [--test-clean-install] [--output-dir ] [-h|--help]" + echo "Usage: $0 --os --pg --version [--test-clean-install] [--output-dir ] [-h|--help]" echo "" echo "Description:" echo " This script builds extension packages (DEB/RPM) using Docker." @@ -12,9 +12,9 @@ function show_help { echo "Mandatory Arguments:" echo " --os OS to build packages for. Possible values: [deb11, deb12, ubuntu22.04, ubuntu24.04, rhel8, rhel9]" echo " --pg PG version to build packages for. Possible values: [15, 16, 17]" + echo " --version The version of documentdb to build. Examples: [0.100.0, 0.101.0]" echo "" echo "Optional Arguments:" - echo " --version The version of documentdb to build. Examples: [0.100.0, 0.101.0]" echo " --test-clean-install Test installing the packages in a clean Docker container." echo " --output-dir Relative path from the repo root of the directory where to drop the packages. The directory will be created if it doesn't exist. Default: packaging" echo " -h, --help Display this help message." @@ -97,16 +97,10 @@ if [[ -z "$PG" ]]; then exit 1 fi -# get the version from control file if [[ -z "$DOCUMENTDB_VERSION" ]]; then - DOCUMENTDB_VERSION=$(grep -E "^default_version" pg_documentdb_core/documentdb_core.control | sed -E "s/.*'([0-9]+\.[0-9]+-[0-9]+)'.*/\1/") - DOCUMENTDB_VERSION=$(echo $DOCUMENTDB_VERSION | sed "s/-/./g") - echo "DOCUMENTDB_VERSION extracted from control file: $DOCUMENTDB_VERSION" - if [[ -z "$DOCUMENTDB_VERSION" ]]; then - echo "Error: --version is required and could not be found in the control file." - show_help - exit 1 - fi + echo "Error: --version is required." + show_help + exit 1 fi # Set the appropriate Docker image and configuration based on the OS @@ -147,8 +141,6 @@ elif [[ "$PACKAGE_TYPE" == "rpm" ]]; then esac fi -TAG=documentdb-build-packages-$OS-pg$PG:latest - repo_root=$(git rev-parse --show-toplevel) abs_output_dir="$repo_root/$OUTPUT_DIR" cd "$repo_root" @@ -204,16 +196,16 @@ if [[ $TEST_CLEAN_INSTALL == true ]]; then exit 1 fi package_rel_path="$OUTPUT_DIR/$rpm_package_name" - + echo "RPM package path for testing: $package_rel_path" - + # Build the Docker image while showing the output to the console docker build -t documentdb-test-rpm-packages:latest -f packaging/test_packages/Dockerfile_test_install_rpm_packages \ --build-arg BASE_IMAGE="$DOCKER_IMAGE" \ --build-arg POSTGRES_VERSION="$PG" \ --build-arg RPM_PACKAGE_REL_PATH="$package_rel_path" \ --build-arg OS_VERSION_ARG="$OS_VERSION_NUMBER" . - + # Run the Docker container to test the packages docker run --rm --env POSTGRES_VERSION="$PG" documentdb-test-rpm-packages:latest fi @@ -221,4 +213,4 @@ if [[ $TEST_CLEAN_INSTALL == true ]]; then echo "Clean installation test successful!!" fi -echo "Packages are available in $abs_output_dir" \ No newline at end of file +echo "Packages are available in $abs_output_dir" diff --git a/packaging/debian_files/changelog b/packaging/debian_files/changelog old mode 100755 new mode 100644 index f16f8bd51..d31b7d7df --- a/packaging/debian_files/changelog +++ b/packaging/debian_files/changelog @@ -10,7 +10,7 @@ documentdb (0.104-0) unstable; urgency=medium * Enable rum_enable_index_scan as default on *[Perf]* * Add public `documentdb-local` Docker image with gateway to GHCR * Support `compact` command *[Feature]*. Requires `documentdb.enablecompact` GUC to be `on`. -* Enable role privileges for `usersInfo` command *[Feature]* +* Enable role privileges for `usersInfo` command *[Feature]* -- Shuai Tian Mon, 09 Jun 2025 12:00:00 +0000 @@ -47,7 +47,7 @@ documentdb (0.102-0) unstable; urgency=medium * Support the $dateFromString operator with full functionality [Feature] * Support extended syntax for $getField aggregation operator (field as expression) [Feature] - -- Shuai Tian Wed, 26 Mar 2025 10:00:00 +0000 + -- FerretDB Packages Wed, 26 Mar 2025 10:00:00 +0000 documentdb (0.101-0) unstable; urgency=medium @@ -58,10 +58,10 @@ documentdb (0.101-0) unstable; urgency=medium * Skip loading documents if group expression is constant [Perf] * Fix Merge stage not outputting to target collection [Bugfix] (#20) - -- Shuai Tian Tue, 12 Feb 2025 10:00:00 +0000 + -- FerretDB Packages Tue, 12 Feb 2025 10:00:00 +0000 documentdb (0.100-0) unstable; urgency=medium * Initial release - -- Shuai Tian Thu, 23 Jan 2025 10:00:00 +0000 \ No newline at end of file + -- FerretDB Packages Thu, 23 Jan 2025 10:00:00 +0000 diff --git a/packaging/debian_files/compat b/packaging/debian_files/compat old mode 100755 new mode 100644 index 3cacc0b93..48082f72f --- a/packaging/debian_files/compat +++ b/packaging/debian_files/compat @@ -1 +1 @@ -12 \ No newline at end of file +12 diff --git a/packaging/debian_files/control b/packaging/debian_files/control old mode 100755 new mode 100644 index 959ba2e7e..c7719d2eb --- a/packaging/debian_files/control +++ b/packaging/debian_files/control @@ -2,9 +2,9 @@ Source: documentdb Section: database Priority: optional Build-Depends: debhelper (>= 11), postgresql-server-dev-POSTGRES_VERSION -Maintainer: Shuai Tian +Maintainer: FerretDB Packages Package: postgresql-POSTGRES_VERSION-documentdb Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, postgresql-POSTGRES_VERSION, postgresql-POSTGRES_VERSION-cron, postgresql-POSTGRES_VERSION-pgvector, postgresql-POSTGRES_VERSION-postgis-3, postgresql-POSTGRES_VERSION-rum -Description: DocumentDB is the open-source engine powering vCore-based Azure Cosmos DB for MongoDB. It offers a native implementation of document-oriented NoSQL database, enabling seamless CRUD operations on BSON data types within a PostgreSQL framework. \ No newline at end of file +Description: DocumentDB is the open-source engine powering vCore-based Azure Cosmos DB for MongoDB. It offers a native implementation of document-oriented NoSQL database, enabling seamless CRUD operations on BSON data types within a PostgreSQL framework. diff --git a/packaging/debian_files/rules b/packaging/debian_files/rules old mode 100755 new mode 100644 index 3478d0506..363dd034d --- a/packaging/debian_files/rules +++ b/packaging/debian_files/rules @@ -7,4 +7,4 @@ override_dh_auto_test: make install adduser --disabled-password --gecos "" documentdb chown -R documentdb:documentdb . - su documentdb -c "make check" \ No newline at end of file + su documentdb -c "make check" diff --git a/packaging/packaging-entrypoint.sh b/packaging/packaging-entrypoint.sh index 2b0b5fb1e..0bd083629 100755 --- a/packaging/packaging-entrypoint.sh +++ b/packaging/packaging-entrypoint.sh @@ -27,4 +27,4 @@ mkdir -p /output cp *.deb /output/ # Change ownership of the output files to match the host user's UID and GID -chown -R $(stat -c "%u:%g" /output) /output \ No newline at end of file +chown -R $(stat -c "%u:%g" /output) /output diff --git a/packaging/test_packages/Dockerfile_test_install_deb_packages b/packaging/test_packages/Dockerfile_test_install_deb_packages old mode 100755 new mode 100644 index e52cd6543..c0792fc4b --- a/packaging/test_packages/Dockerfile_test_install_deb_packages +++ b/packaging/test_packages/Dockerfile_test_install_deb_packages @@ -44,4 +44,4 @@ RUN dpkg -i ${DEB_PACKAGE_REL_PATH} COPY packaging/test_packages/test-install-entrypoint.sh /usr/local/bin/test-install-entrypoint.sh -ENTRYPOINT ["test-install-entrypoint.sh"] \ No newline at end of file +ENTRYPOINT ["test-install-entrypoint.sh"] diff --git a/packaging/test_packages/test-install-entrypoint.sh b/packaging/test_packages/test-install-entrypoint.sh index a894e6e28..fd22dfc86 100755 --- a/packaging/test_packages/test-install-entrypoint.sh +++ b/packaging/test_packages/test-install-entrypoint.sh @@ -10,4 +10,4 @@ sed -i '/internal/d' Makefile # Run the test adduser --disabled-password --gecos "" documentdb chown -R documentdb:documentdb . -su documentdb -c "make check" \ No newline at end of file +su documentdb -c "make check" diff --git a/pg_documentdb/src/commands/coll_mod.c b/pg_documentdb/src/commands/coll_mod.c index ad42ec5d0..ff8656883 100644 --- a/pg_documentdb/src/commands/coll_mod.c +++ b/pg_documentdb/src/commands/coll_mod.c @@ -191,7 +191,7 @@ command_coll_mod(PG_FUNCTION_ARGS) pgbson_writer writer; PgbsonWriterInit(&writer); - PgbsonWriterAppendInt32(&writer, "ok", 2, 1); + PgbsonWriterAppendDouble(&writer, "ok", 2, 1); if (specFlags == HAS_NO_OPTIONS) { diff --git a/pg_documentdb/src/commands/coll_stats.c b/pg_documentdb/src/commands/coll_stats.c index 90ee71f2b..3bdcb9c32 100644 --- a/pg_documentdb/src/commands/coll_stats.c +++ b/pg_documentdb/src/commands/coll_stats.c @@ -914,7 +914,7 @@ BuildEmptyResponseMessage(CollStatsResult *result) PgbsonWriterAppendInt32(&writer, "totalIndexSize", 14, 0); PgbsonWriterAppendDocument(&writer, "indexSizes", 10, PgbsonInitEmpty()); PgbsonWriterAppendInt32(&writer, "scaleFactor", 11, result->scaleFactor); - PgbsonWriterAppendInt32(&writer, "ok", 2, result->ok); + PgbsonWriterAppendDouble(&writer, "ok", 2, result->ok); return PgbsonWriterGetPgbson(&writer); } @@ -931,7 +931,7 @@ BuildResponseMessage(CollStatsResult *result) PgbsonWriterAppendUtf8(&writer, "ns", 2, result->ns); WriteCoreStorageStats(result, &writer); - PgbsonWriterAppendInt32(&writer, "ok", 2, result->ok); + PgbsonWriterAppendDouble(&writer, "ok", 2, result->ok); return PgbsonWriterGetPgbson(&writer); } diff --git a/pg_documentdb/src/commands/create_indexes.c b/pg_documentdb/src/commands/create_indexes.c index 822306bb5..6a6cb9752 100644 --- a/pg_documentdb/src/commands/create_indexes.c +++ b/pg_documentdb/src/commands/create_indexes.c @@ -5810,7 +5810,7 @@ MakeCreateIndexesMsg(CreateIndexesResult *result) PgbsonWriterAppendUtf8(&writer, "note", strlen("note"), result->note); } - PgbsonWriterAppendInt32(&writer, "ok", strlen("ok"), result->ok); + PgbsonWriterAppendDouble(&writer, "ok", 2, result->ok); if (!result->ok) { @@ -5860,7 +5860,7 @@ MakeCreateIndexesMsg(CreateIndexesResult *result) PgbsonWriterEndDocument(&outerWriter, &indexIdWriter); } - PgbsonWriterAppendInt32(&outerWriter, "ok", strlen("ok"), result->ok); + PgbsonWriterAppendDouble(&outerWriter, "ok", 2, result->ok); return PgbsonWriterGetPgbson(&outerWriter); } @@ -5918,7 +5918,7 @@ MakeReIndexMsg(ReIndexResult *result) PgbsonWriterEndArray(&writer, &indexesWriter); } - PgbsonWriterAppendInt32(&writer, "ok", strlen("ok"), result->ok); + PgbsonWriterAppendDouble(&writer, "ok", 2, result->ok); if (!result->ok) { diff --git a/pg_documentdb/src/commands/create_indexes_background.c b/pg_documentdb/src/commands/create_indexes_background.c index 7958f8b0e..cfdd150b4 100644 --- a/pg_documentdb/src/commands/create_indexes_background.c +++ b/pg_documentdb/src/commands/create_indexes_background.c @@ -1465,13 +1465,13 @@ MakeBuildIndexesMsg(BuildIndexesResult *result) /* { "raw" : * { "defaultShard" : * { - * "ok" : { "$numberInt" : "0" }, + * "ok" : { "$numberDouble" : "0" }, * "errmsg" : "error", * "code" : { "$numberInt" : "1" } * } * }, * "finish" : { "$numberInt" : "1" }, - * "ok" : { "$numberInt" : "0" } + * "ok" : { "$numberDouble" : "0" } * } */ pgbson_writer outerWriter; @@ -1487,7 +1487,7 @@ MakeBuildIndexesMsg(BuildIndexesResult *result) PgbsonWriterStartDocument(&rawShardResultWriter, "defaultShard", strlen( "defaultShard"), &writer); - PgbsonWriterAppendInt32(&writer, "ok", strlen("ok"), result->ok); + PgbsonWriterAppendDouble(&writer, "ok", 2, result->ok); if (result->errcode == ERRCODE_T_R_DEADLOCK_DETECTED) { result->errmsg = "deadlock detected. createIndexes() command " @@ -1508,7 +1508,7 @@ MakeBuildIndexesMsg(BuildIndexesResult *result) PgbsonWriterEndDocument(&outerWriter, &rawShardResultWriter); } PgbsonWriterAppendInt32(&outerWriter, FinishKey, FinishKeyLength, result->finish); - PgbsonWriterAppendInt32(&outerWriter, "ok", strlen("ok"), result->ok); + PgbsonWriterAppendDouble(&outerWriter, "ok", 2, result->ok); return PgbsonWriterGetPgbson(&outerWriter); } diff --git a/pg_documentdb/src/commands/db_stats.c b/pg_documentdb/src/commands/db_stats.c index 6d6694497..121e65f8c 100644 --- a/pg_documentdb/src/commands/db_stats.c +++ b/pg_documentdb/src/commands/db_stats.c @@ -406,7 +406,7 @@ BuildResponseMessage(DbStatsResult *result) PgbsonWriterAppendDouble(&writer, "indexSize", 9, result->indexSize); PgbsonWriterAppendDouble(&writer, "totalSize", 9, result->totalSize); PgbsonWriterAppendInt32(&writer, "scaleFactor", 11, result->scaleFactor); - PgbsonWriterAppendInt32(&writer, "ok", 2, result->ok); + PgbsonWriterAppendDouble(&writer, "ok", 2, result->ok); return PgbsonWriterGetPgbson(&writer); } diff --git a/pg_documentdb/src/commands/drop_indexes.c b/pg_documentdb/src/commands/drop_indexes.c index 0e898cdd7..538747542 100644 --- a/pg_documentdb/src/commands/drop_indexes.c +++ b/pg_documentdb/src/commands/drop_indexes.c @@ -762,7 +762,7 @@ MakeDropIndexesMsg(DropIndexesResult *result) { pgbson_writer writer; PgbsonWriterInit(&writer); - PgbsonWriterAppendBool(&writer, "ok", strlen("ok"), result->ok); + PgbsonWriterAppendDouble(&writer, "ok", 2, result->ok); if (result->ok) { diff --git a/pg_documentdb/src/commands/find_and_modify.c b/pg_documentdb/src/commands/find_and_modify.c index 252115ec5..94337a8e7 100644 --- a/pg_documentdb/src/commands/find_and_modify.c +++ b/pg_documentdb/src/commands/find_and_modify.c @@ -629,7 +629,7 @@ BuildResponseMessage(FindAndModifyResult *result) result->value); } - PgbsonWriterAppendDouble(&resultWriter, "ok", strlen("ok"), result->ok); + PgbsonWriterAppendDouble(&resultWriter, "ok", 2, result->ok); return PgbsonWriterGetPgbson(&resultWriter); } diff --git a/pg_documentdb/src/commands/update.c b/pg_documentdb/src/commands/update.c index 6f1171536..ce5da20a4 100644 --- a/pg_documentdb/src/commands/update.c +++ b/pg_documentdb/src/commands/update.c @@ -2644,7 +2644,7 @@ SerializeBatchUpdateResult(BatchUpdateResult *result) PgbsonWriterInit(&writer); PgbsonWriterAppendDocument(&writer, "response", -1, BuildResponseMessage(result)); - PgbsonWriterAppendBool(&writer, "ok", -1, result->writeErrors == NIL); + PgbsonWriterAppendDouble(&writer, "ok", 2, result->writeErrors == NIL); return PgbsonWriterGetPgbson(&writer); } diff --git a/pg_documentdb/src/commands/users.c b/pg_documentdb/src/commands/users.c index f31390928..14556aaaf 100644 --- a/pg_documentdb/src/commands/users.c +++ b/pg_documentdb/src/commands/users.c @@ -326,7 +326,7 @@ documentdb_extension_create_user(PG_FUNCTION_ARGS) { pgbson_writer finalWriter; PgbsonWriterInit(&finalWriter); - PgbsonWriterAppendInt32(&finalWriter, "ok", 2, 0); + PgbsonWriterAppendDouble(&finalWriter, "ok", 2, 0); PgbsonWriterAppendUtf8(&finalWriter, "errmsg", 6, "External identity providers are not supported"); PgbsonWriterAppendInt32(&finalWriter, "code", 4, 115); @@ -385,7 +385,7 @@ documentdb_extension_create_user(PG_FUNCTION_ARGS) pgbson_writer finalWriter; PgbsonWriterInit(&finalWriter); - PgbsonWriterAppendInt32(&finalWriter, "ok", 2, 1); + PgbsonWriterAppendDouble(&finalWriter, "ok", 2, 1); PG_RETURN_POINTER(PgbsonWriterGetPgbson(&finalWriter)); } @@ -689,7 +689,7 @@ documentdb_extension_drop_user(PG_FUNCTION_ARGS) { pgbson_writer finalWriter; PgbsonWriterInit(&finalWriter); - PgbsonWriterAppendInt32(&finalWriter, "ok", 2, 0); + PgbsonWriterAppendDouble(&finalWriter, "ok", 2, 0); PgbsonWriterAppendUtf8(&finalWriter, "errmsg", 6, "External identity providers are not supported"); PgbsonWriterAppendInt32(&finalWriter, "code", 4, 115); @@ -721,7 +721,7 @@ documentdb_extension_drop_user(PG_FUNCTION_ARGS) pgbson_writer finalWriter; PgbsonWriterInit(&finalWriter); - PgbsonWriterAppendInt32(&finalWriter, "ok", 2, 1); + PgbsonWriterAppendDouble(&finalWriter, "ok", 2, 1); PG_RETURN_POINTER(PgbsonWriterGetPgbson(&finalWriter)); } @@ -948,7 +948,7 @@ UpdateNativeUser(UpdateUserSpec *spec) pgbson_writer finalWriter; PgbsonWriterInit(&finalWriter); - PgbsonWriterAppendInt32(&finalWriter, "ok", 2, 1); + PgbsonWriterAppendDouble(&finalWriter, "ok", 2, 1); PG_RETURN_POINTER(PgbsonWriterGetPgbson(&finalWriter)); } @@ -995,7 +995,7 @@ documentdb_extension_get_users(PG_FUNCTION_ARGS) if (userInfoDatum == (Datum) 0) { - PgbsonWriterAppendInt32(&finalWriter, "ok", 2, 1); + PgbsonWriterAppendDouble(&finalWriter, "ok", 2, 1); pgbson *result = PgbsonWriterGetPgbson(&finalWriter); PG_RETURN_POINTER(result); } @@ -1085,7 +1085,7 @@ documentdb_extension_get_users(PG_FUNCTION_ARGS) PgbsonWriterEndArray(&finalWriter, &userArrayWriter); } - PgbsonWriterAppendInt32(&finalWriter, "ok", 2, 1); + PgbsonWriterAppendDouble(&finalWriter, "ok", 2, 1); pgbson *result = PgbsonWriterGetPgbson(&finalWriter); PG_RETURN_POINTER(result); }