Skip to content

Commit

Permalink
feat: minor changes
Browse files Browse the repository at this point in the history
  • Loading branch information
yogeshpaliyal committed Mar 3, 2024
1 parent fed85ac commit 84ab85d
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 33 deletions.
34 changes: 8 additions & 26 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "typescript-action",
"description": "GitHub Actions TypeScript template",
"version": "0.0.0",
"version": "0.0.1",
"author": "",
"private": true,
"homepage": "https://github.com/actions/typescript-action",
Expand All @@ -12,11 +12,7 @@
"bugs": {
"url": "https://github.com/actions/typescript-action/issues"
},
"keywords": [
"actions",
"node",
"setup"
],
"keywords": ["actions", "node", "setup"],
"exports": {
".": "./dist/index.js"
},
Expand All @@ -33,37 +29,23 @@
"package": "ncc build src/index.ts --license licenses.txt",
"package:watch": "npm run package -- --watch",
"test": "jest",
"all": "npm run format:write && npm run lint && npm run test && npm run coverage && npm run package"
"all": "npm run format:write && npm run test && npm run coverage && npm run package"
},
"license": "MIT",
"jest": {
"preset": "ts-jest",
"verbose": true,
"clearMocks": true,
"testEnvironment": "node",
"moduleFileExtensions": [
"js",
"ts"
],
"testMatch": [
"**/*.test.ts"
],
"testPathIgnorePatterns": [
"/node_modules/",
"/dist/"
],
"moduleFileExtensions": ["js", "ts"],
"testMatch": ["**/*.test.ts"],
"testPathIgnorePatterns": ["/node_modules/", "/dist/"],
"transform": {
"^.+\\.ts$": "ts-jest"
},
"coverageReporters": [
"json-summary",
"text",
"lcov"
],
"coverageReporters": ["json-summary", "text", "lcov"],
"collectCoverage": true,
"collectCoverageFrom": [
"./src/**"
]
"collectCoverageFrom": ["./src/**"]
},
"dependencies": {
"@actions/core": "^1.10.1",
Expand Down
160 changes: 160 additions & 0 deletions src/io-utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { Dirent } from 'fs'

Check failure on line 1 in src/io-utils.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

'fs' imported multiple times
import fs from 'fs'

Check failure on line 2 in src/io-utils.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

'fs' imported multiple times
import * as glob from '@actions/glob'

Check failure on line 3 in src/io-utils.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Unable to resolve path to module '@actions/glob'
import { stat } from 'fs'

Check failure on line 4 in src/io-utils.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

'fs' imported multiple times
import * as path from 'path'

const stats = promisify(stat)
import { debug, info } from '@actions/core'

Check failure on line 8 in src/io-utils.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Import in body of module; reorder to top
import { promisify } from 'util'

Check failure on line 9 in src/io-utils.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Import in body of module; reorder to top
import { dirname } from 'path'

Check failure on line 10 in src/io-utils.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Import in body of module; reorder to top


Check failure on line 12 in src/io-utils.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Delete `⏎`
export function findReleaseFiles(releaseDir: string): Dirent[] | undefined {
const releaseFiles = fs
Expand All @@ -13,3 +22,154 @@ export function findReleaseFiles(releaseDir: string): Dirent[] | undefined {
return releaseFiles
}
}

/**
* If multiple paths are specific, the least common ancestor (LCA) of the search paths is used as
* the delimiter to control the directory structure for the artifact. This function returns the LCA
* when given an array of search paths
*
* Example 1: The patterns `/foo/` and `/bar/` returns `/`
*
* Example 2: The patterns `~/foo/bar/*` and `~/foo/voo/two/*` and `~/foo/mo/` returns `~/foo`
*/
function getMultiPathLCA(searchPaths: string[]): string {
if (searchPaths.length < 2) {
throw new Error('At least two search paths must be provided')
}

const commonPaths = new Array<string>()
const splitPaths = new Array<string[]>()
let smallestPathLength = Number.MAX_SAFE_INTEGER

// split each of the search paths using the platform specific separator
for (const searchPath of searchPaths) {
debug(`Using search path ${ searchPath }`)

Check failure on line 46 in src/io-utils.ts

View workflow job for this annotation

GitHub Actions / Lint Codebase

Replace `·searchPath·` with `searchPath`

const splitSearchPath = path.normalize(searchPath).split(path.sep)

// keep track of the smallest path length so that we don't accidentally later go out of bounds
smallestPathLength = Math.min(smallestPathLength, splitSearchPath.length)
splitPaths.push(splitSearchPath)
}

// on Unix-like file systems, the file separator exists at the beginning of the file path, make sure to preserve it
if (searchPaths[0].startsWith(path.sep)) {
commonPaths.push(path.sep)
}

let splitIndex = 0

// function to check if the paths are the same at a specific index
function isPathTheSame(): boolean {
const compare = splitPaths[0][splitIndex]
for (let i = 1; i < splitPaths.length; i++) {
if (compare !== splitPaths[i][splitIndex]) {
// a non-common index has been reached
return false
}
}
return true
}

// loop over all the search paths until there is a non-common ancestor or we go out of bounds
while (splitIndex < smallestPathLength) {
if (!isPathTheSame()) {
break
}
// if all are the same, add to the end result & increment the index
commonPaths.push(splitPaths[0][splitIndex])
splitIndex++
}
return path.join(...commonPaths)
}

function getDefaultGlobOptions(): glob.GlobOptions {
return {
followSymbolicLinks: true,
implicitDescendants: true,
omitBrokenSymbolicLinks: true
}
}

export interface SearchResult {
filesToUpload: string[]
rootDirectory: string
}

export async function findFilesToUpload(
searchPath: string,
globOptions?: glob.GlobOptions
): Promise<SearchResult> {
const searchResults: string[] = []
const globber = await glob.create(
searchPath,
globOptions || getDefaultGlobOptions()
)
const rawSearchResults: string[] = await globber.glob()

/*
Files are saved with case insensitivity. Uploading both a.txt and A.txt will files to be overwritten
Detect any files that could be overwritten for user awareness
*/
const set = new Set<string>()

/*
Directories will be rejected if attempted to be uploaded. This includes just empty
directories so filter any directories out from the raw search results
*/
for (const searchResult of rawSearchResults) {
const fileStats = await stats(searchResult)
// isDirectory() returns false for symlinks if using fs.lstat(), make sure to use fs.stat() instead
if (!fileStats.isDirectory()) {
debug(`File:${ searchResult } was found using the provided searchPath`)
searchResults.push(searchResult)

// detect any files that would be overwritten because of case insensitivity
if (set.has(searchResult.toLowerCase())) {
info(
`Uploads are case insensitive: ${ searchResult } was detected that it will be overwritten by another file with the same path`
)
} else {
set.add(searchResult.toLowerCase())
}
} else {
debug(
`Removing ${ searchResult } from rawSearchResults because it is a directory`
)
}
}

// Calculate the root directory for the artifact using the search paths that were utilized
const searchPaths: string[] = globber.getSearchPaths()

if (searchPaths.length > 1) {
info(
`Multiple search paths detected. Calculating the least common ancestor of all paths`
)
const lcaSearchPath = getMultiPathLCA(searchPaths)
info(
`The least common ancestor is ${ lcaSearchPath }. This will be the root directory of the artifact`
)

return {
filesToUpload: searchResults,
rootDirectory: lcaSearchPath
}
}

/*
Special case for a single file artifact that is uploaded without a directory or wildcard pattern. The directory structure is
not preserved and the root directory will be the single files parent directory
*/
if (searchResults.length === 1 && searchPaths[0] === searchResults[0]) {
return {
filesToUpload: searchResults,
rootDirectory: dirname(searchResults[0])
}
}

return {
filesToUpload: searchResults,
rootDirectory: searchPaths[0]
}
}
17 changes: 10 additions & 7 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import * as core from '@actions/core'
import { wait } from './wait'
import * as fs from 'fs'
import path from 'path'
import { readFileSync, lstatSync } from 'fs'
const axios = require('axios')
const FormData = require('form-data')
import { findReleaseFiles } from './io-utils'

/**
* The main function for the action.
* @returns {Promise<void>} Resolves when the action is complete.
*/
export async function run(): Promise<void> {
try {
const axios = require('axios')
const FormData = require('form-data')

const apiKey: string = core.getInput('apiKey')
const packageName: string = core.getInput('packageName')
const aabFile: string = core.getInput('aabFile')
Expand All @@ -20,17 +20,20 @@ export async function run(): Promise<void> {
const keystoreAlias: string = core.getInput('keystoreAlias')
const keystorePassword: string = core.getInput('keystorePassword')

const axios = require('axios')

const headers = {
Authorization: `Bearer ${apiKey}`
}

const signingKey = path.join('signingFile', 'signingKey.jks')
fs.writeFileSync(signingKey, signingKeyBase64, 'base64')

const releaseFiles = findReleaseFiles(aabFile)
if (!releaseFiles || releaseFiles.length || releaseFiles.length !== 1) {
throw new Error('No release files found')
}

const formData = new FormData()
formData.append('file', fs.createReadStream(aabFile))
formData.append('file', fs.createReadStream(releaseFiles[0].path))
formData.append('file', fs.createReadStream(signingKey))
formData.append('keyPassword', keyPassword)
formData.append('keystoreAlias', keystoreAlias)
Expand Down

0 comments on commit 84ab85d

Please sign in to comment.