mirror of
https://github.com/JamesIves/github-pages-deploy-action.git
synced 2023-12-15 20:03:39 +08:00
Feat: add support for absolute paths (#449)
* Feat: add support for absolute paths
* Refactor: `generateFolderPath` to generic function
`action.root` is initialized at e42fda2d72/src/constants.ts (L98)
, so it should not be an optional property.
* Test: rm unnecessary tests
* Refactor: rm unused exports
This commit is contained in:
parent
b96b1d043d
commit
118cd3f75b
@ -178,51 +178,6 @@ describe('git', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('should fail if the build folder begins with a /', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
accessToken: '123',
|
||||
repositoryPath: 'JamesIves/github-pages-deploy-action',
|
||||
branch: 'branch',
|
||||
folder: '/',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
await init(action)
|
||||
} catch (e) {
|
||||
expect(execute).toBeCalledTimes(0)
|
||||
expect(e.message).toMatch(
|
||||
"There was an error initializing the repository: Incorrectly formatted build folder. The deployment folder cannot be prefixed with '/' or './'. Instead reference the folder name directly. ❌"
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should fail if the build folder begins with a ./', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
accessToken: '123',
|
||||
branch: 'branch',
|
||||
folder: './',
|
||||
pusher: {
|
||||
name: 'asd',
|
||||
email: 'as@cat'
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
await init(action)
|
||||
} catch (e) {
|
||||
expect(execute).toBeCalledTimes(0)
|
||||
expect(e.message).toMatch(
|
||||
"There was an error initializing the repository: Incorrectly formatted build folder. The deployment folder cannot be prefixed with '/' or './'. Instead reference the folder name directly. ❌"
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
it('should not fail if root is used', async () => {
|
||||
Object.assign(action, {
|
||||
silent: false,
|
||||
|
@ -2,6 +2,7 @@ import {
|
||||
isNullOrUndefined,
|
||||
generateTokenType,
|
||||
generateRepositoryPath,
|
||||
generateFolderPath,
|
||||
suppressSensitiveInformation
|
||||
} from '../src/util'
|
||||
|
||||
@ -177,4 +178,67 @@ describe('util', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('generateFolderPath', () => {
|
||||
it('should return absolute path if folder name is provided', () => {
|
||||
const action = {
|
||||
branch: '123',
|
||||
root: '.',
|
||||
workspace: 'src/',
|
||||
folder: 'build',
|
||||
gitHubToken: null,
|
||||
accessToken: null,
|
||||
ssh: null,
|
||||
silent: false
|
||||
}
|
||||
expect(generateFolderPath(action, 'folder')).toEqual('src/build')
|
||||
})
|
||||
|
||||
it('should return original path if folder name begins with /', () => {
|
||||
const action = {
|
||||
branch: '123',
|
||||
root: '.',
|
||||
workspace: 'src/',
|
||||
folder: '/home/user/repo/build',
|
||||
gitHubToken: null,
|
||||
accessToken: null,
|
||||
ssh: null,
|
||||
silent: false
|
||||
}
|
||||
expect(generateFolderPath(action, 'folder')).toEqual(
|
||||
'/home/user/repo/build'
|
||||
)
|
||||
})
|
||||
|
||||
it('should process as relative path if folder name begins with ./', () => {
|
||||
const action = {
|
||||
branch: '123',
|
||||
root: '.',
|
||||
workspace: 'src/',
|
||||
folder: './build',
|
||||
gitHubToken: null,
|
||||
accessToken: null,
|
||||
ssh: null,
|
||||
silent: false
|
||||
}
|
||||
expect(generateFolderPath(action, 'folder')).toEqual('src/build')
|
||||
})
|
||||
|
||||
it('should return absolute path if folder name begins with ~', () => {
|
||||
const action = {
|
||||
branch: '123',
|
||||
root: '.',
|
||||
workspace: 'src/',
|
||||
folder: '~/repo/build',
|
||||
gitHubToken: null,
|
||||
accessToken: null,
|
||||
ssh: null,
|
||||
silent: false
|
||||
}
|
||||
process.env.HOME = '/home/user'
|
||||
expect(generateFolderPath(action, 'folder')).toEqual(
|
||||
'/home/user/repo/build'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -39,7 +39,7 @@ export interface ActionInterface {
|
||||
/** The fully qualified repositpory path, this gets auto generated if repositoryName is provided. */
|
||||
repositoryPath?: string
|
||||
/** The root directory where your project lives. */
|
||||
root?: string
|
||||
root: string
|
||||
/** Wipes the commit history from the deployment branch in favor of a single commit. */
|
||||
singleCommit?: boolean | null
|
||||
/** Determines if the action should run in silent mode or not. */
|
||||
@ -109,6 +109,10 @@ export const action: ActionInterface = {
|
||||
workspace: process.env.GITHUB_WORKSPACE || ''
|
||||
}
|
||||
|
||||
export type ActionFolders = NonNullable<
|
||||
Pick<ActionInterface, 'folder' | 'root'>
|
||||
>
|
||||
|
||||
/** Status codes for the action. */
|
||||
export enum Status {
|
||||
SUCCESS = 'success',
|
||||
|
11
src/git.ts
11
src/git.ts
@ -4,6 +4,7 @@ import fs from 'fs'
|
||||
import {ActionInterface, Status} from './constants'
|
||||
import {execute} from './execute'
|
||||
import {
|
||||
generateFolderPath,
|
||||
hasRequiredParameters,
|
||||
isNullOrUndefined,
|
||||
suppressSensitiveInformation
|
||||
@ -130,6 +131,8 @@ export async function generateBranch(action: ActionInterface): Promise<void> {
|
||||
|
||||
/* Runs the necessary steps to make the deployment. */
|
||||
export async function deploy(action: ActionInterface): Promise<Status> {
|
||||
const folderPath = generateFolderPath(action, 'folder')
|
||||
const rootPath = generateFolderPath(action, 'root')
|
||||
const temporaryDeploymentDirectory =
|
||||
'github-pages-deploy-action-temp-deployment-folder'
|
||||
const temporaryDeploymentBranch = `github-pages-deploy-action/${Math.random()
|
||||
@ -229,22 +232,22 @@ export async function deploy(action: ActionInterface): Promise<Status> {
|
||||
Allows the user to specify the root if '.' is provided.
|
||||
rsync is used to prevent file duplication. */
|
||||
await execute(
|
||||
`rsync -q -av --checksum --progress ${action.folder}/. ${
|
||||
`rsync -q -av --checksum --progress ${folderPath}/. ${
|
||||
action.targetFolder
|
||||
? `${temporaryDeploymentDirectory}/${action.targetFolder}`
|
||||
: temporaryDeploymentDirectory
|
||||
} ${
|
||||
action.clean
|
||||
? `--delete ${excludes} ${
|
||||
!fs.existsSync(`${action.folder}/CNAME`) ? '--exclude CNAME' : ''
|
||||
!fs.existsSync(`${folderPath}/CNAME`) ? '--exclude CNAME' : ''
|
||||
} ${
|
||||
!fs.existsSync(`${action.folder}/.nojekyll`)
|
||||
!fs.existsSync(`${folderPath}/.nojekyll`)
|
||||
? '--exclude .nojekyll'
|
||||
: ''
|
||||
}`
|
||||
: ''
|
||||
} --exclude .ssh --exclude .git --exclude .github ${
|
||||
action.folder === action.root
|
||||
folderPath === rootPath
|
||||
? `--exclude ${temporaryDeploymentDirectory}`
|
||||
: ''
|
||||
}`,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {exportVariable, info, setFailed} from '@actions/core'
|
||||
import {action, ActionInterface, Status} from './constants'
|
||||
import {deploy, generateBranch, init} from './git'
|
||||
import {deploy, init} from './git'
|
||||
import {generateRepositoryPath, generateTokenType} from './util'
|
||||
|
||||
/** Initializes and runs the action.
|
||||
@ -53,5 +53,3 @@ export default async function run(
|
||||
exportVariable('DEPLOYMENT_STATUS', status)
|
||||
}
|
||||
}
|
||||
|
||||
export {init, deploy, generateBranch, ActionInterface}
|
||||
|
23
src/util.ts
23
src/util.ts
@ -1,5 +1,6 @@
|
||||
import path from 'path'
|
||||
import {isDebug} from '@actions/core'
|
||||
import {ActionInterface} from './constants'
|
||||
import {ActionInterface, ActionFolders} from './constants'
|
||||
|
||||
const replaceAll = (input: string, find: string, replace: string): string =>
|
||||
input.split(find).join(replace)
|
||||
@ -26,6 +27,20 @@ export const generateRepositoryPath = (action: ActionInterface): string =>
|
||||
action.accessToken || `x-access-token:${action.gitHubToken}`
|
||||
}@github.com/${action.repositoryName}.git`
|
||||
|
||||
/* Genetate absolute folder path by the provided folder name */
|
||||
export const generateFolderPath = <K extends keyof ActionFolders>(
|
||||
action: ActionInterface,
|
||||
key: K
|
||||
): string => {
|
||||
const folderName = action[key]
|
||||
const folderPath = path.isAbsolute(folderName)
|
||||
? folderName
|
||||
: folderName.startsWith('~')
|
||||
? folderName.replace('~', process.env.HOME as string)
|
||||
: path.join(action.workspace, folderName)
|
||||
return folderPath
|
||||
}
|
||||
|
||||
/* Checks for the required tokens and formatting. Throws an error if any case is matched. */
|
||||
export const hasRequiredParameters = (action: ActionInterface): void => {
|
||||
if (
|
||||
@ -47,12 +62,6 @@ export const hasRequiredParameters = (action: ActionInterface): void => {
|
||||
if (!action.folder || isNullOrUndefined(action.folder)) {
|
||||
throw new Error('You must provide the action with a folder to deploy.')
|
||||
}
|
||||
|
||||
if (action.folder.startsWith('/') || action.folder.startsWith('./')) {
|
||||
throw new Error(
|
||||
"Incorrectly formatted build folder. The deployment folder cannot be prefixed with '/' or './'. Instead reference the folder name directly."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/* Suppresses sensitive information from being exposed in error messages. */
|
||||
|
Loading…
Reference in New Issue
Block a user