name: ⚖️ Compare Bun Version description: Compare the installed Bun version against a version specification. inputs: bun-version: description: The version spec to compare against (e.g., '1.1.0', 'canary', '>1.2.0', '1.x'). required: true runs: using: composite steps: - name: 🛠️ Get installed Bun version and revision id: bun shell: bash run: | echo "version=$(bun --version | tr -d '\r\n')" >> $GITHUB_OUTPUT echo "revision=$(bun --revision 2>/dev/null || true)" >> $GITHUB_OUTPUT - name: ⚖️ Compare versions shell: bash env: REQUESTED_SPEC: ${{ inputs.bun-version }} ACTUAL_VERSION: ${{ steps.bun.outputs.version }} ACTUAL_REVISION: ${{ steps.bun.outputs.revision }} run: | set -euo pipefail # Function to compare two semantic versions (e.g., version_compare 1.2.3 1.10.0) # Returns: 0 if v1 == v2, 1 if v1 > v2, 2 if v1 < v2 version_compare() { if [[ "$1" == "$2" ]]; then return 0; fi local lowest=$(printf '%s\n' "$1" "$2" | sort -V | head -n1) if [[ "$1" == "$lowest" ]]; then return 2; else return 1; fi } echo "Requested spec: ${REQUESTED_SPEC}" echo "Actual version: ${ACTUAL_VERSION}" # Case 1: 'latest' - always passes if [[ "${REQUESTED_SPEC}" == "latest" ]]; then echo "OK: Skipping explicit version check for 'latest'." exit 0 fi # Case 2: 'canary' - check for 'canary' in revision or version string if [[ "${REQUESTED_SPEC}" == "canary" ]]; then if [[ "${ACTUAL_REVISION}" == *canary* ]] || [[ "${ACTUAL_VERSION}" == *canary* ]]; then echo "OK: Detected canary build (version: ${ACTUAL_VERSION}, revision: ${ACTUAL_REVISION:-n/a})." exit 0 else echo "Error: Expected a canary build, but got ${ACTUAL_VERSION} (revision: ${ACTUAL_REVISION:-n/a})." exit 1 fi fi # Case 3: Semver ranges (e.g., >1.0.0, <2, 1.x, 1.1.0) op_part=$(echo "${REQUESTED_SPEC}" | sed -E 's/^([><=]*).*/\1/') version_part=$(echo "${REQUESTED_SPEC}" | sed -E 's/^[><= ]*//') op="${op_part:-==}" version_base="${version_part//.x/}" # Handle wildcards like '1.x' or '1' if [[ "${version_part}" == *.x* ]] || { [[ ! "${version_part}" == *.* ]] && [[ "${op}" == "==" ]]; }; then if [[ "${ACTUAL_VERSION}" == "${version_base}" || "${ACTUAL_VERSION}" == "${version_base}".* ]]; then echo "OK: Version ${ACTUAL_VERSION} matches wildcard spec '${REQUESTED_SPEC}'." exit 0 else echo "Error: Version ${ACTUAL_VERSION} does not match wildcard spec '${REQUESTED_SPEC}'." exit 1 fi fi # Perform comparison for >, <, >=, <=, == version_compare "${ACTUAL_VERSION}" "${version_part}" && result=0 || result=$? case "${op}" in '==') if [[ ${result} -ne 0 ]]; then echo "Error: Expected version ${version_part}, but got ${ACTUAL_VERSION}." && exit 1; fi ;; '>') if [[ ${result} -ne 1 ]]; then echo "Error: Expected version > ${version_part}, but got ${ACTUAL_VERSION}." && exit 1; fi ;; '<') if [[ ${result} -ne 2 ]]; then echo "Error: Expected version < ${version_part}, but got ${ACTUAL_VERSION}." && exit 1; fi ;; '>=') if [[ ${result} -eq 2 ]]; then echo "Error: Expected version >= ${version_part}, but got ${ACTUAL_VERSION}." && exit 1; fi ;; '<=') if [[ ${result} -eq 1 ]]; then echo "Error: Expected version <= ${version_part}, but got ${ACTUAL_VERSION}." && exit 1; fi ;; *) echo "Error: Unsupported operator '${op}' in spec '${REQUESTED_SPEC}'." && exit 1 ;; esac echo "OK: Version ${ACTUAL_VERSION} satisfies spec '${REQUESTED_SPEC}'."