1+ import { readFileSync } from 'node:fs'
12import { defineConfig } from 'vite'
23import react from '@vitejs/plugin-react'
34import istanbul from 'vite-plugin-istanbul'
45import * as path from 'path'
6+ function readTextFile ( filePath : string ) : string | undefined {
7+ try {
8+ return readFileSync ( filePath , 'utf8' ) . trim ( ) || undefined
9+ } catch {
10+ return undefined
11+ }
12+ }
13+
14+ function resolveSpaVersionDisplay ( {
15+ packageVersion,
16+ commitSha,
17+ exactTag,
18+ refName,
19+ refType
20+ } : {
21+ packageVersion ?: string
22+ commitSha ?: string
23+ exactTag ?: string
24+ refName ?: string
25+ refType ?: string
26+ } ) : string {
27+ const releaseTag = refType === 'tag' ? refName : exactTag
28+ const normalizedReleaseTag = releaseTag ?. replace ( / ^ r e f s \/ t a g s \/ / , '' ) . replace ( / ^ v / , '' )
29+
30+ if ( packageVersion && normalizedReleaseTag === packageVersion ) {
31+ return packageVersion
32+ }
33+
34+ if ( commitSha ) {
35+ return commitSha
36+ }
37+
38+ return packageVersion ?? 'unknown'
39+ }
40+
41+ function resolveProjectRoot ( configDir : string ) : string {
42+ const candidates = [ configDir , path . resolve ( configDir , '..' ) , path . resolve ( configDir , '../..' ) ]
43+
44+ const projectRoot = candidates . find ( ( candidate ) => {
45+ return Boolean ( readTextFile ( path . join ( candidate , 'package.json' ) ) ) && Boolean ( readTextFile ( path . join ( candidate , '.git' ) ) )
46+ } )
47+
48+ return projectRoot ?? configDir
49+ }
50+
51+ function readPackageVersion ( projectRoot : string ) : string | undefined {
52+ try {
53+ const packageJson = JSON . parse ( readFileSync ( path . join ( projectRoot , 'package.json' ) , 'utf8' ) ) as {
54+ version ?: string
55+ }
56+
57+ return packageJson . version
58+ } catch {
59+ return undefined
60+ }
61+ }
62+
63+ function resolveGitDir ( projectRoot : string ) : string | undefined {
64+ const dotGitPath = path . join ( projectRoot , '.git' )
65+ const dotGitContent = readTextFile ( dotGitPath )
66+
67+ if ( dotGitContent ?. startsWith ( 'gitdir: ' ) ) {
68+ return path . resolve ( projectRoot , dotGitContent . slice ( 'gitdir: ' . length ) )
69+ }
70+
71+ return dotGitContent ? undefined : dotGitPath
72+ }
73+
74+ function readPackedRef ( gitDir : string , ref : string ) : string | undefined {
75+ const packedRefs = readTextFile ( path . join ( gitDir , 'packed-refs' ) )
76+
77+ if ( ! packedRefs ) {
78+ return undefined
79+ }
80+
81+ for ( const line of packedRefs . split ( '\n' ) ) {
82+ if ( ! line || line . startsWith ( '#' ) || line . startsWith ( '^' ) ) {
83+ continue
84+ }
85+
86+ const [ sha , packedRef ] = line . split ( ' ' )
87+ if ( packedRef === ref ) {
88+ return sha
89+ }
90+ }
91+
92+ return undefined
93+ }
94+
95+ function readGitHeadInfo ( projectRoot : string ) : { commitSha ?: string ; exactTag ?: string } {
96+ const gitDir = resolveGitDir ( projectRoot )
97+
98+ if ( ! gitDir ) {
99+ return { }
100+ }
101+
102+ const head = readTextFile ( path . join ( gitDir , 'HEAD' ) )
103+
104+ if ( ! head ) {
105+ return { }
106+ }
107+
108+ if ( ! head . startsWith ( 'ref: ' ) ) {
109+ return { commitSha : head . slice ( 0 , 9 ) }
110+ }
111+
112+ const ref = head . slice ( 'ref: ' . length )
113+ const commitSha = readTextFile ( path . join ( gitDir , ref ) ) ?? readPackedRef ( gitDir , ref )
114+ const exactTag = ref . startsWith ( 'refs/tags/' ) ? ref . replace ( 'refs/tags/' , '' ) : undefined
115+
116+ return {
117+ commitSha : commitSha ?. slice ( 0 , 9 ) ,
118+ exactTag
119+ }
120+ }
121+
122+ const projectRoot = resolveProjectRoot ( __dirname )
123+ const packageVersion = readPackageVersion ( projectRoot )
124+ const gitHeadInfo = readGitHeadInfo ( projectRoot )
125+ const shortCommitSha = process . env . GITHUB_SHA ?. slice ( 0 , 9 ) ?? gitHeadInfo . commitSha
126+ const exactTag =
127+ ( process . env . GITHUB_REF_TYPE === 'tag' ? process . env . GITHUB_REF_NAME : undefined ) ??
128+ gitHeadInfo . exactTag
129+ const spaDisplayVersion = resolveSpaVersionDisplay ( {
130+ packageVersion,
131+ commitSha : shortCommitSha ,
132+ exactTag,
133+ refName : process . env . GITHUB_REF_NAME ,
134+ refType : process . env . GITHUB_REF_TYPE
135+ } )
5136
6137export default defineConfig ( {
138+ root : projectRoot ,
139+ define : {
140+ 'import.meta.env.VITE_APP_VERSION' : JSON . stringify ( packageVersion ) ,
141+ 'import.meta.env.VITE_COMMIT_SHA_SHORT' : JSON . stringify ( shortCommitSha ) ,
142+ 'import.meta.env.VITE_GIT_EXACT_TAG' : JSON . stringify ( exactTag ) ,
143+ 'import.meta.env.VITE_GITHUB_REF_NAME' : JSON . stringify ( process . env . GITHUB_REF_NAME ) ,
144+ 'import.meta.env.VITE_GITHUB_REF_TYPE' : JSON . stringify ( process . env . GITHUB_REF_TYPE ) ,
145+ 'import.meta.env.VITE_SPA_DISPLAY_VERSION' : JSON . stringify ( spaDisplayVersion )
146+ } ,
7147 plugins : [
8148 react ( ) ,
9149 istanbul ( {
@@ -24,8 +164,8 @@ export default defineConfig({
24164 } ,
25165 resolve : {
26166 alias : {
27- '@' : path . resolve ( __dirname , 'src' ) ,
28- '@tests' : path . resolve ( __dirname , 'tests' )
167+ '@' : path . resolve ( projectRoot , 'src' ) ,
168+ '@tests' : path . resolve ( projectRoot , 'tests' )
29169 }
30170 }
31171} )
0 commit comments