diff --git a/.dockerignore b/.dockerignore index 6c2c947b..86645f05 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,6 @@ +# NOTE: do not add .git here. The Dockerfile's `versioner` stage runs +# `git describe` against it to stamp the build version (issue #1014); excluding +# it makes every build report "unknown". docs documentMD **/node_modules diff --git a/.github/workflows/build_and_deploy.yml b/.github/workflows/build_and_deploy.yml index 4b006cdb..0f79db63 100644 --- a/.github/workflows/build_and_deploy.yml +++ b/.github/workflows/build_and_deploy.yml @@ -16,25 +16,23 @@ jobs: steps: - uses: actions/checkout@v4 - uses: eWaterCycle/setup-apptainer@v2 - - name: stamp version.json for this build - # main is branch-protected (rejects direct pushes even from Actions bots), - # so this can't be committed back - it only needs to be baked into the - # artifacts built below, which the Dockerfile's `COPY server server` picks up - # from this worktree. + - name: determine version number for this build + # This value is baked into the image via the WHEEL_VERSION build-arg (see + # the docker build step) and into source.tar.gz below. It is never + # committed back: main is branch-protected, and the per-branch + # `[skip ci] update version number` commits used to conflict on + # server/app/db/version.json between parallel PRs (issue #1014). run: | case "${BRANCH_NAME}" in main) TYPE=release ;; maintenance*) TYPE=maintenance ;; *) TYPE=beta ;; esac - VERSION_NUMBER="$(date '+%Y-%m%d-%H%M%S')-${TYPE}" - echo "{\"version\": \"${VERSION_NUMBER}\" }" > server/app/db/version.json - cat server/app/db/version.json - echo "VERSION_NUMBER=${VERSION_NUMBER}" >>$GITHUB_ENV + echo "VERSION_NUMBER=$(date '+%Y-%m%d-%H%M%S')-${TYPE}" >>$GITHUB_ENV # only main builds (TYPE=release) own the `latest` docker tag and the # GitHub "Latest" release; maintenance*/beta builds must not. echo "RELEASE_TYPE=${TYPE}" >>$GITHUB_ENV - - run: docker build -t ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${BRANCH_NAME} . + - run: docker build --build-arg WHEEL_VERSION="${VERSION_NUMBER}" -t ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${BRANCH_NAME} . - run: docker login -u ${DOCKER_USER_NAME} -p ${DOCKER_PASSWORD} - run: docker push ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${BRANCH_NAME} - name: publish :latest for mainline releases only @@ -45,7 +43,16 @@ jobs: docker push ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:latest - run: docker save ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${BRANCH_NAME} | gzip > wheel_docker.tar.gz - run: apptainer build wheel.sif docker-daemon://${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${BRANCH_NAME} - - run: git archive --format=tar.gz --prefix=OpenWHEEL-${BRANCH_NAME}/ -o source.tar.gz HEAD + - name: pack source.tar.gz with the version baked in + # git archive would ship the committed placeholder version.json; extract + # the tracked tree, drop in the real version, and re-pack so a run from + # source.tar.gz reports the same version as the images (issue #1014). + run: | + rm -rf _src && mkdir -p _src + git archive --prefix=OpenWHEEL-${BRANCH_NAME}/ HEAD | tar -x -C _src + echo "{\"version\": \"${VERSION_NUMBER}\" }" > _src/OpenWHEEL-${BRANCH_NAME}/server/app/db/version.json + tar -czf source.tar.gz -C _src OpenWHEEL-${BRANCH_NAME} + rm -rf _src - name: create release and upload artifact uses: softprops/action-gh-release@v2 with: diff --git a/.github/workflows/run_test.yml b/.github/workflows/run_test.yml index c0a20d41..619eb17e 100644 --- a/.github/workflows/run_test.yml +++ b/.github/workflows/run_test.yml @@ -21,7 +21,6 @@ jobs: WHEEL_TEST_REMOTEHOST: testServer WHEEL_TEST_REMOTE_PASSWORD: passw0rd TZ: JST-9 - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} runs-on: ubuntu-latest strategy: matrix: @@ -102,31 +101,6 @@ jobs: fi } >> "$GITHUB_STEP_SUMMARY" echo "DEBUG: step summary write exit code: $?, file now has $(wc -l < "$GITHUB_STEP_SUMMARY") lines" - - name: determine release type from branch name - run: | - case "${{ github.ref_name }}" in - main) TYPE=release ;; - maintenance*) TYPE=maintenance ;; - *) TYPE=beta ;; - esac - echo "VERSION_NUMBER=$(date '+%Y-%m%d-%H%M%S')-${TYPE}" >>$GITHUB_ENV - - run: cat server/app/db/version.json - - name: update version.json - id: create-json - uses: jsdaniell/create-json@v1.2.2 - with: - dir: "server/app/db" - name: "version.json" - json: '{"version": "${{ env.VERSION_NUMBER }}" }' - - run: cat server/app/db/version.json - - name: commit and push version.json - run: | - git remote set-url origin https://github-actions:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY} - git config user.name 'version-number-updater[bot]' - git config user.email 'action@github.com' - git add server/app/db/version.json - git commit -m '[skip ci] update version number' - git push origin HEAD:${GITHUB_REF} backup: needs: ["test"] runs-on: ubuntu-latest diff --git a/AGENTS.md b/AGENTS.md index 65808254..cfe5ef54 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,7 +19,7 @@ test/cypress/component component test with cypress - if you make new functions under server, you have to add unit tests for them. - if you make changes that affect the UI, you have to add component tests for them. - never commit, revert or make any other operations to git repo without explicitly order from user. -- do not change "server/app/db/version.json" this file is automatically updated by github workflow. +- do not hand-edit "server/app/db/version.json". It holds a fixed development placeholder in the repo; the real value is baked in only at build time (Dockerfile / build_and_deploy.yml), never by a running CI job. See documentMD/design/design.md ("バージョン番号の管理"). - Do not use conditional skip in unit tests except for pre-existing ones. ## implementation policy diff --git a/Dockerfile b/Dockerfile index 843b5d37..e11f157f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,6 +17,20 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt -y install curl git rsy # bind-mounted home. No-op when the socket is absent. RUN printf '\n[ -S /tmp/wheel-ssh-agent.sock ] && export SSH_AUTH_SOCK=/tmp/wheel-ssh-agent.sock\n' >> /etc/bash.bashrc +# Resolve one version string for this build from the .git in the build context. +# This happens at build time so the value is frozen into the image (static, not +# recomputed at server start). Everything in this stage is discarded except +# /wheel-version - the copied .git never reaches the final image. See issue #1014. +# (Do not add .git to .dockerignore or every build falls back to "unknown".) +# No --dirty: git describe would inspect the working tree, but .dockerignore +# hides tracked paths (documentMD/ etc.) from `COPY . .`, so --dirty would always +# fire. The abbreviated commit is enough to identify the source. +FROM base AS versioner +WORKDIR /wheel-src +COPY . . +RUN git describe --tags --always --long --abbrev=12 > /wheel-version 2>/dev/null \ + || echo unknown > /wheel-version + FROM base AS run_base WORKDIR /usr/src/ COPY package.json package.json @@ -46,6 +60,18 @@ WORKDIR /usr/src COPY common common COPY client client COPY server server +# bake the build version (issue #1014): +# - WHEEL_VERSION build-arg wins (CI passes the release/beta string) +# - else the git-derived value from the versioner stage, marked -local +# - else leave version.json as shipped (committed placeholder, or a +# source.tar.gz that already carries a baked version) +COPY --from=versioner /wheel-version /tmp/wheel-version +ARG WHEEL_VERSION= +RUN if [ -n "${WHEEL_VERSION}" ]; then \ + printf '{"version": "%s" }\n' "${WHEEL_VERSION}" > server/app/db/version.json ; \ + elif [ "$(cat /tmp/wheel-version)" != unknown ]; then \ + printf '{"version": "%s-local" }\n' "$(cat /tmp/wheel-version)" > server/app/db/version.json ; \ + fi WORKDIR /usr/src/client RUN npm run build COPY entrypoint.sh /usr/src/server/ @@ -65,6 +91,14 @@ FROM run_base AS exec WORKDIR /usr/src COPY common common COPY server server +# bake the build version - same rule as the dev stage (issue #1014) +COPY --from=versioner /wheel-version /tmp/wheel-version +ARG WHEEL_VERSION= +RUN if [ -n "${WHEEL_VERSION}" ]; then \ + printf '{"version": "%s" }\n' "${WHEEL_VERSION}" > server/app/db/version.json ; \ + elif [ "$(cat /tmp/wheel-version)" != unknown ]; then \ + printf '{"version": "%s-local" }\n' "$(cat /tmp/wheel-version)" > server/app/db/version.json ; \ + fi # Don't prune - keep all dependencies to avoid ESM resolution issues COPY --from=builder /usr/src/server/app/public /usr/src/server/app/public COPY entrypoint.sh /usr/src/server/ diff --git a/README.md b/README.md index ff48a28d..389c55b6 100644 --- a/README.md +++ b/README.md @@ -86,8 +86,3 @@ run following commands 3. cd test; npm install (install e2e test modules) please read [TEST_GUIDE.md](TEST_GUIDE.md) for test execution guide (UT and E2E) - - -### CI/CD process -when you push new commit to github, server/app/db/version.json will be updated during CI/CD process. -So, you have to pull before make further commit. diff --git a/TEST_GUIDE.md b/TEST_GUIDE.md index f7239d2c..4fbb4a28 100644 --- a/TEST_GUIDE.md +++ b/TEST_GUIDE.md @@ -94,7 +94,6 @@ npm run UT:local-gfarm トリガー: main以外の全ブランチへのpush SSH テストサーバー: naoso5/openpbs (port 4000:22) 実行コマンド: npm run test (server/) -成功後: server/app/db/version.json を自動更新 ``` #### Windows (`run_test_windows.yml`) diff --git a/documentMD/design/design.md b/documentMD/design/design.md index d1c791c6..a010f50e 100644 --- a/documentMD/design/design.md +++ b/documentMD/design/design.md @@ -608,6 +608,38 @@ saveボタンの押下 | git commit revertボタンの押下 | git reset HEAD --hard cleanボタンの押下 | rm -fr && git reset HEAD --hard +## バージョン番号の管理 +サーバ起動時のログ(`starting WHEEL server (version X)`)とログ画面の「about」で +表示するバージョン番号は、`server/app/core/versionInfo.js` が +`server/app/db/version.json` の `version` を読んで使っているだけである。 + +リポジトリに commit されている値は固定のプレースホルダで、CI を含め誰もこの +ファイルを書き換えない。 + +```json +{"version": "not defined - this is a development build"} +``` + +(過去は `run_test.yml` が push のたびに日付ベースの値を各ブランチへ +commit-back していたが、並行して出している複数の PR が `version.json` で +必ず conflict するのと、merge のたびに stale な値が main / maintenance に +乗ってしまう問題があったため廃止した。GitLab issue `aicshud/WHEEL#1014`。) + +実際に表示される文字列は、実行経路ごとに **ビルド時** に焼き込まれる。 +アプリのコードが起動時にバージョンを計算することはない。 + +| 実行経路 | version.json を書くのは | 表示される文字列 | +|---|---|---| +| 公式リリース(`build_and_deploy.yml`) | CI が `docker build --build-arg WHEEL_VERSION=...` で渡す | `YYYY-MMDD-HHMMSS-{release\|maintenance\|beta}`(GitHub Release のタグと一致) | +| `docker build .`(`.git` あり・build-arg なし) | Dockerfile の `versioner` ステージが `git describe` した値 | `-local` | +| `docker build --build-arg WHEEL_VERSION=... .` | Dockerfile(build-arg 優先) | 渡した値そのまま | +| `source.tar.gz` を展開して build | CI が焼き込んだ値を保持 | `YYYY-MMDD-HHMMSS-{type}` | +| ソースから直接 `npm start`(ビルドなし) | 誰も書かない(プレースホルダのまま) | `not defined - this is a development build` | +| `compose.dev.yml` での開発 | 上記と同じ(`server/app` を bind mount するため、イメージに焼き込まれた値は隠れる) | `not defined - this is a development build` | + +`server/app/db/version.json` は手で書き換えない。中身はビルド処理が焼き込む +ものであり、リポジトリ上の値は「ビルドされていない」ことを示すプレースホルダ +として固定してある。 ## 画面遷移 ![画面遷移図](./screen_transition.svg) diff --git a/documentMD/design/developer_guide.md b/documentMD/design/developer_guide.md index d77fe697..65968c3c 100644 --- a/documentMD/design/developer_guide.md +++ b/documentMD/design/developer_guide.md @@ -144,7 +144,7 @@ OpenWHEEL/ ### 必須ルール 1. コード変更後は必ずlintを実行する 2. 関数には JSDoc コメントを付ける -3. `server/app/db/version.json` は変更しない(GitHub Workflowが自動更新) +3. `server/app/db/version.json` は変更しない(固定プレースホルダを commit してあり、実際の値はビルド時に焼き込まれる。詳細は design.md「バージョン番号の管理」参照) ### 実装スタイル diff --git a/documentMD/design/testing.md b/documentMD/design/testing.md index ada10f40..a266a695 100644 --- a/documentMD/design/testing.md +++ b/documentMD/design/testing.md @@ -164,7 +164,6 @@ describe("My Feature", () => { トリガー: main以外の全ブランチへのpush SSHテストサーバー: naoso5/openpbs(port 4000:22) 実行コマンド: npm run test(server/) -成功後: server/app/db/version.json を自動更新 ``` ### E2Eテスト(`run_cypress.yml`) diff --git a/server/app/db/version.json b/server/app/db/version.json index 2df01726..527f5a11 100644 --- a/server/app/db/version.json +++ b/server/app/db/version.json @@ -1 +1 @@ -{"version": "2026-0910-204642-beta" } \ No newline at end of file +{"version": "not defined - this is a development build"}