diff --git a/.github/workflows/build_and_deploy.yml b/.github/workflows/build_and_deploy.yml index 0f79db63..23ff3e0b 100644 --- a/.github/workflows/build_and_deploy.yml +++ b/.github/workflows/build_and_deploy.yml @@ -4,6 +4,10 @@ on: pull_request_target: types: - closed + branches: + - main + - "maint/**" + - "dev/**" jobs: build_and_deploy: if: github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true @@ -16,42 +20,54 @@ jobs: steps: - uses: actions/checkout@v4 - uses: eWaterCycle/setup-apptainer@v2 - - name: determine version number for this build + - name: determine version number and release type 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). + # + # SAFE_BRANCH_NAME strips "/" from BRANCH_NAME - dev/YYYY and maint/YYYY + # contain a slash, which Docker tags (and, less critically, the source + # tarball's top-level directory name) cannot contain. run: | case "${BRANCH_NAME}" in main) TYPE=release ;; - maintenance*) TYPE=maintenance ;; + maint/*) TYPE=maintenance ;; + dev/*) TYPE=beta ;; *) TYPE=beta ;; esac + case "${TYPE}" in + release) TITLE_PREFIX="✅ Release" ;; + maintenance) TITLE_PREFIX="🔧 Maintenance" ;; + beta) TITLE_PREFIX="🧪 Beta" ;; + esac + echo "SAFE_BRANCH_NAME=$(echo "${BRANCH_NAME}" | tr '/' '-')" >>$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 --build-arg WHEEL_VERSION="${VERSION_NUMBER}" -t ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${BRANCH_NAME} . + echo "TITLE_PREFIX=${TITLE_PREFIX}" >>$GITHUB_ENV + - run: docker build --build-arg WHEEL_VERSION="${VERSION_NUMBER}" -t ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${SAFE_BRANCH_NAME} . - run: docker login -u ${DOCKER_USER_NAME} -p ${DOCKER_PASSWORD} - - run: docker push ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${BRANCH_NAME} + - run: docker push ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${SAFE_BRANCH_NAME} - name: publish :latest for mainline releases only if: env.RELEASE_TYPE == 'release' run: | - docker tag ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${BRANCH_NAME} \ + docker tag ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${SAFE_BRANCH_NAME} \ ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:latest 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: docker save ${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${SAFE_BRANCH_NAME} | gzip > wheel_docker.tar.gz + - run: apptainer build wheel.sif docker-daemon://${DOCKER_USER_NAME}/${DOCKER_CONTAINER_NAME}:${SAFE_BRANCH_NAME} - 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} + git archive --prefix=OpenWHEEL-${SAFE_BRANCH_NAME}/ HEAD | tar -x -C _src + echo "{\"version\": \"${VERSION_NUMBER}\" }" > _src/OpenWHEEL-${SAFE_BRANCH_NAME}/server/app/db/version.json + tar -czf source.tar.gz -C _src OpenWHEEL-${SAFE_BRANCH_NAME} rm -rf _src - name: create release and upload artifact uses: softprops/action-gh-release@v2 @@ -61,13 +77,14 @@ jobs: wheel_docker.tar.gz source.tar.gz tag_name: ${{ env.VERSION_NUMBER }} - name: ${{ env.VERSION_NUMBER }} + name: "${{ env.TITLE_PREFIX }} ${{ env.VERSION_NUMBER }}" body: "release for ${{ github.ref_name }} @ ${{ github.sha }} (${{ env.VERSION_NUMBER }})" - # only the main line is the "Latest" release; maintenance*/beta ship - # as pre-releases so they never take the badge or the /releases/latest - # redirect (v1 silently ignored these inputs). + # only the main line ever takes the "Latest" badge and the + # /releases/latest redirect (v1 silently ignored these inputs). + # maintenance backports are real, non-draft releases (not "pre"), they + # just never become "Latest" - only beta (dev/YYYY) is marked prerelease. make_latest: ${{ env.RELEASE_TYPE == 'release' }} - prerelease: ${{ env.RELEASE_TYPE != 'release' }} + prerelease: ${{ env.RELEASE_TYPE == 'beta' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} backup: diff --git a/AGENTS.md b/AGENTS.md index d3794076..ac4ca607 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,6 +21,7 @@ test/cypress/component component test with cypress - never commit, revert or make any other operations to git repo without explicitly order from user. - 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. +- Follow the branch strategy documented in README.md's "Branch strategy" section strictly (which branch to target for feature work vs. hotfixes, naming, no direct commits to `dev/YYYY`/`maint/YYYY`). ## implementation policy - always write code in async/await style diff --git a/README.md b/README.md index 389c55b6..4e5b5a05 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,14 @@ Any other markdown files under documentMD is detailed informatin for developpers "client" and "server" has client and server code respectively. "test" contains E2E test code based on cypress, you can find server-side unit test code under server/test +### Branch strategy +- `main` reflects the latest published release. It only moves forward when a release is cut - either by merging in `dev/YYYY` at a cycle-end release, or by merging a `maint/YYYY` hotfix line forward for a patch release. Do not open feature/bugfix pull requests directly against `main` - see below for where changes should target instead. +- `dev/YYYY` is the active development branch for fiscal year YYYY, branched off `main`. All feature and bugfix pull requests during an active development cycle target this branch. +- Once `dev/YYYY`'s cycle is done, it is merged into `main` (a release point) and then renamed in place (not re-created) to `maint/YYYY`, becoming a hotfix-only branch that receives no new features. +- From that rename until the next `dev/YYYY+1` is created, any hotfix targets the current `maint/YYYY`, not `main` directly. +- Both `dev/YYYY` and `maint/YYYY` are protected: no direct commits/pushes, changes only land via reviewed pull requests. +- `maintenance2023` and `maintenance2026` predate this naming rule and are kept as-is (legacy exceptions); any new long-lived release-maintenance branch going forward uses the `maint/YYYY` scheme. + ### preparation run following commands 1. npm install