feat: initial version
Some checks failed
Continuous Integration / TypeScript Tests (push) Failing after 38s
Continuous Integration / GitHub Actions Test (push) Failing after 7s
Check Transpiled JavaScript / Check dist/ (push) Successful in 1m29s

This commit is contained in:
Peter 2024-05-02 18:38:23 +02:00
commit 2fc1d51eb6
Signed by: prskr
GPG key ID: F56BED6903BC5E37
37 changed files with 66401 additions and 0 deletions

View file

@ -0,0 +1,41 @@
{
"name": "GitHub Actions (TypeScript)",
"image": "mcr.microsoft.com/devcontainers/typescript-node:20",
"postCreateCommand": "npm install",
"customizations": {
"codespaces": {
"openFiles": ["README.md"]
},
"vscode": {
"extensions": [
"bierner.markdown-preview-github-styles",
"davidanson.vscode-markdownlint",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"github.copilot",
"github.copilot-chat",
"github.vscode-github-actions",
"github.vscode-pull-request-github",
"me-dutour-mathieu.vscode-github-actions",
"redhat.vscode-yaml",
"rvest.vs-code-prettier-eslint",
"yzhang.markdown-all-in-one"
],
"settings": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2,
"editor.formatOnSave": true,
"markdown.extension.list.indentationSize": "adaptive",
"markdown.extension.italic.indicator": "_",
"markdown.extension.orderedList.marker": "one"
}
}
},
"remoteEnv": {
"GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}"
},
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers-contrib/features/prettier:1": {}
}
}

4
.eslintignore Normal file
View file

@ -0,0 +1,4 @@
lib/
dist/
node_modules/
coverage/

View file

@ -0,0 +1,72 @@
# In TypeScript actions, `dist/` is a special directory. When you reference
# an action with the `uses:` property, `dist/index.js` is the code that will be
# run. For this project, the `dist/index.js` file is transpiled from other
# source files. This workflow ensures the `dist/` directory contains the
# expected transpiled code.
#
# If this workflow is run from a feature branch, it will act as an additional CI
# check and fail if the checked-in `dist/` directory does not match what is
# expected from the build.
name: Check Transpiled JavaScript
on:
pull_request:
branches:
- main
push:
branches:
- main
permissions:
contents: read
jobs:
check-dist:
name: Check dist/
runs-on: ubuntu-latest
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v4
- name: Setup Node.js
id: setup-node
uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: npm
- name: Install Dependencies
id: install
run: npm ci
- name: Build dist/ Directory
id: build
run: npm run bundle
# This will fail the workflow if the `dist/` directory is different than
# expected.
- name: Compare Directories
id: diff
run: |
if [ ! -d dist/ ]; then
echo "Expected dist/ directory does not exist. See status below:"
ls -la ./
exit 1
fi
if [ "$(git diff --ignore-space-at-eol --text dist/ | wc -l)" -gt "0" ]; then
echo "Detected uncommitted changes after build. See status below:"
git diff --ignore-space-at-eol --text dist/
exit 1
fi
# If `dist/` was different than expected, upload the expected version as a
# workflow artifact.
- if: ${{ failure() && steps.diff.outcome == 'failure' }}
name: Upload Artifact
id: upload
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

64
.forgejo/workflows/ci.yml Normal file
View file

@ -0,0 +1,64 @@
name: Continuous Integration
on:
pull_request:
branches:
- main
push:
branches:
- main
permissions:
contents: read
jobs:
test-typescript:
name: TypeScript Tests
runs-on: ubuntu-latest
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v4
- name: Setup Node.js
id: setup-node
uses: actions/setup-node@v4
with:
node-version-file: .node-version
cache: npm
- name: Install Dependencies
id: npm-ci
run: npm ci
- name: Check Format
id: npm-format-check
run: npm run format:check
- name: Lint
id: npm-lint
run: npm run lint
- name: Test
id: npm-ci-test
run: npm run ci-test
test-action:
name: GitHub Actions Test
runs-on: ubuntu-latest
steps:
- name: Checkout
id: checkout
uses: actions/checkout@v4
- name: Test Local Action
id: test-action
uses: ./
with:
milliseconds: 2000
- name: Print Output
id: output
run: echo "${{ steps.test-action.outputs.time }}"

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
* text=auto eol=lf
dist/** filter=lfs diff=lfs merge=lfs -text

103
.gitignore vendored Normal file
View file

@ -0,0 +1,103 @@
# Dependency directory
node_modules
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# OS metadata
.DS_Store
Thumbs.db
# Ignore built ts files
__tests__/runner/*
# IDE files
.idea
.vscode
*.code-workspace

1
.node-version Normal file
View file

@ -0,0 +1 @@
20.6.0

3
.prettierignore Normal file
View file

@ -0,0 +1,3 @@
dist/
node_modules/
coverage/

16
.prettierrc.json Normal file
View file

@ -0,0 +1,16 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "none",
"bracketSpacing": true,
"bracketSameLine": true,
"arrowParens": "avoid",
"proseWrap": "always",
"htmlWhitespaceSensitivity": "css",
"endOfLine": "lf"
}

9
LICENSE Normal file
View file

@ -0,0 +1,9 @@
MIT License
Copyright (c) 2024 prskr
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

1
README.md Normal file
View file

@ -0,0 +1 @@
# setup-hugo

View file

@ -0,0 +1,39 @@
import { OctokitReleaseLookup } from '../src/asset-lookup'
import { Platform } from '../src/os'
import { HugoReleaseTransformer } from '../src/hugo'
import { DartSass, Hugo } from '../src/constants'
import { DartSassReleaseTransformer } from '../src/dart-sass'
beforeEach(() => {
jest.resetModules()
})
describe('Asset lookup', () => {
test('Hugo: should return valid version', async () => {
const octoVersionDetermination = new OctokitReleaseLookup()
const release = await octoVersionDetermination.getRelease(
Hugo.Org,
Hugo.Repo,
'',
HugoReleaseTransformer
)
expect(release.tag_name).toMatch(new RegExp('\\d+.\\d+.\\d+'))
const archiveUrl = release.assetUrl(new Platform(), false)
expect(archiveUrl).not.toBe(undefined)
})
test('Dart-Sass: should return valid version', async () => {
const octoVersionDetermination = new OctokitReleaseLookup()
const release = await octoVersionDetermination.getRelease(
DartSass.Org,
DartSass.Repo,
'',
DartSassReleaseTransformer
)
expect(release.tag_name).toMatch(new RegExp('\\d+.\\d+.\\d+'))
const archiveUrl = release.assetUrl(new Platform())
expect(archiveUrl).not.toBe(undefined)
})
})

17
__tests__/index.test.ts Normal file
View file

@ -0,0 +1,17 @@
/**
* Unit tests for the action's entrypoint, src/index.ts
*/
import * as main from '../src/main'
// Mock the action's entrypoint
const runMock = jest.spyOn(main, 'run').mockImplementation()
describe('index', () => {
it('calls run when imported', async () => {
// eslint-disable-next-line @typescript-eslint/no-require-imports
require('../src/index.ts')
expect(runMock).toHaveBeenCalled()
})
})

23
__tests__/os.test.ts Normal file
View file

@ -0,0 +1,23 @@
import { Platform } from '../src/os'
beforeEach(() => {
jest.resetModules()
})
describe('Platform', () => {
test('getHomeDir - should return non-empty string', () => {
const homeDir = new Platform('linux', undefined, {
HOME: '/home/prskr'
}).getHomeDir()
expect(homeDir).toBe('/home/prskr')
})
test('getHomeDir - return USERPROFILE for win32 platform', () => {
const homeDir = new Platform('win32', undefined, {
USERPROFILE: 'C:\\Users\\prskr'
}).getHomeDir()
expect(homeDir).toBe('C:\\Users\\prskr')
})
})

31
action.yml Normal file
View file

@ -0,0 +1,31 @@
name: 'Hello World'
description: 'Greet someone and record the time'
inputs:
hugo-version:
description:
'The Hugo version to download.ts (if necessary) and use. Example: 0.58.2'
required: false
default: 'latest'
extended:
description:
'Download (if necessary) and use Hugo extended version. Example: true'
required: false
default: 'false'
dart-sass:
description: 'Download (if necessary) dart-sass'
required: false
default: 'false'
dart-sass-version:
description:
'The dart-sass version to download.ts (if necessary) and use. Example:
1.76.0'
required: false
default: ''
github-token:
description:
'Used to avoid rate limits when interacting with the Github API'
required: false
default: ''
runs:
using: 'node20'
main: 'dist/index.js'

BIN
dist/index.js (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
dist/index.js.map (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
dist/licenses.txt (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
dist/package.json (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
dist/sourcemap-register.cjs (Stored with Git LFS) vendored Normal file

Binary file not shown.

53267
lib/index.js Normal file

File diff suppressed because one or more lines are too long

1
lib/index.js.map Normal file

File diff suppressed because one or more lines are too long

1686
lib/licenses.txt Normal file

File diff suppressed because it is too large Load diff

3
lib/package.json Normal file
View file

@ -0,0 +1,3 @@
{
"type": "module"
}

2349
lib/sourcemap-register.cjs Normal file

File diff suppressed because it is too large Load diff

8118
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

93
package.json Normal file
View file

@ -0,0 +1,93 @@
{
"name": "setup-hugo",
"version": "1.0.0",
"description": "",
"private": true,
"keywords": [],
"author": "prskr",
"license": "MIT",
"type": "module",
"engines": {
"node": ">=20"
},
"exports": {
".": "./dist/index.js"
},
"scripts": {
"bundle": "npm run format:write && npm run package",
"ci-test": "npx jest",
"coverage": "npx make-coverage-badge --output-path ./badges/coverage.svg",
"format:write": "npx prettier --write .",
"format:check": "npx prettier --check .",
"lint": "npx eslint . -c ./.github/linters/.eslintrc.yml",
"package": "npx ncc build src/index.ts -o dist --source-map --license licenses.txt",
"package:watch": "npm run package -- --watch",
"test": "npx jest",
"all": "npm run format:write && npm run lint && npm run test && npm run coverage && npm run package"
},
"lint-staged": {
"{src,__tests__}/**/*.ts": [
"prettier --check",
"eslint"
],
"README.md": [
"npx doctoc@2.1.0 --github"
]
},
"jest": {
"preset": "ts-jest",
"verbose": true,
"clearMocks": true,
"testEnvironment": "node",
"moduleFileExtensions": [
"js",
"ts"
],
"testMatch": [
"**/*.test.ts"
],
"testPathIgnorePatterns": [
"/node_modules/",
"/dist/"
],
"transform": {
"^.+\\.ts$": "ts-jest"
},
"coverageReporters": [
"json-summary",
"text",
"lcov"
],
"collectCoverage": true,
"collectCoverageFrom": [
"./src/**"
]
},
"dependencies": {
"@actions/core": "^1.10.1",
"@actions/exec": "^1.1.1",
"@actions/io": "^1.1.3",
"@actions/tool-cache": "^2.0.1",
"octokit": "^3.2.0"
},
"devDependencies": {
"@jest/globals": "^29.7.0",
"@types/jest": "^29.5.12",
"@types/node": "^20.12.7",
"@typescript-eslint/eslint-plugin": "^7.7.1",
"@typescript-eslint/parser": "^7.7.1",
"@vercel/ncc": "^0.38.1",
"eslint": "^8.57.0",
"eslint-plugin-github": "^4.10.2",
"eslint-plugin-jest": "^28.3.0",
"eslint-plugin-jsonc": "^2.15.1",
"eslint-plugin-prettier": "^5.1.3",
"jest": "^29.7.0",
"make-coverage-badge": "^1.2.0",
"nock": "^13.0.10",
"prettier": "^3.2.5",
"prettier-eslint": "^16.3.0",
"ts-jest": "^29.1.2",
"typescript": "^5.4.5"
}
}

59
script/release Normal file
View file

@ -0,0 +1,59 @@
#!/bin/bash
# About:
#
# This is a helper script to tag and push a new release. GitHub Actions use
# release tags to allow users to select a specific version of the action to use.
#
# See: https://github.com/actions/typescript-action#publishing-a-new-release
#
# This script will do the following:
#
# 1. Get the latest release tag
# 2. Prompt the user for a new release tag
# 3. Tag the new release
# 4. Push the new tag to the remote
#
# Usage:
#
# script/release
# Terminal colors
OFF='\033[0m'
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
# Get the latest release tag
latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
if [[ -z "$latest_tag" ]]; then
# There are no existing release tags
echo -e "No tags found (yet) - Continue to create and push your first tag"
latest_tag="[unknown]"
fi
# Display the latest release tag
echo -e "The latest release tag is: ${BLUE}${latest_tag}${OFF}"
# Prompt the user for the new release tag
read -r -p 'Enter a new release tag (vX.X.X format): ' new_tag
# Validate the new release tag
tag_regex='v[0-9]+\.[0-9]+\.[0-9]+$'
if echo "$new_tag" | grep -q -E "$tag_regex"; then
echo -e "Tag: ${BLUE}$new_tag${OFF} is valid"
else
# Release tag is not `vX.X.X` format
echo -e "Tag: ${BLUE}$new_tag${OFF} is ${RED}not valid${OFF} (must be in vX.X.X format)"
exit 1
fi
# Tag the new release
git tag -a "$new_tag" -m "$new_tag Release"
echo -e "${GREEN}Tagged: $new_tag${OFF}"
# Push the new tag to the remote
git push --tags
echo -e "${GREEN}Release tag pushed to remote${OFF}"
echo -e "${GREEN}Done!${OFF}"

46
src/asset-lookup.ts Normal file
View file

@ -0,0 +1,46 @@
import { Octokit } from 'octokit'
import { components } from '@octokit/openapi-types/types'
export interface IGithubRelease {
readonly tag_name: string
}
export interface IReleaseTransformer<T extends IGithubRelease> {
map(release: components['schemas']['release']): T
}
export interface IReleaseLookup {
getRelease<T extends IGithubRelease>(
user: string,
repo: string,
version: string | undefined,
transformer: IReleaseTransformer<T>
): Promise<T>
}
export class OctokitReleaseLookup implements IReleaseLookup {
octokit: Octokit
constructor(pat?: string) {
this.octokit = new Octokit({ auth: pat })
}
async getRelease<T extends IGithubRelease>(
owner: string,
repo: string,
version: string | undefined,
transformer: IReleaseTransformer<T>
): Promise<T> {
const latestRelease = version
? await this.octokit.rest.repos.getReleaseByTag({
owner: owner,
repo: repo,
tag: version
})
: await this.octokit.rest.repos.getLatestRelease({
owner: owner,
repo: repo
})
return transformer.map(latestRelease.data)
}
}

20
src/cache/download.ts vendored Normal file
View file

@ -0,0 +1,20 @@
import * as tc from '@actions/tool-cache'
import { Hugo as HugoTool } from '../constants'
import * as io from '@actions/io'
async function downloadTool(
toolURL: string,
binDir: string,
tempDir: string
): Promise<void> {
const toolAssets: string = await tc.downloadTool(toolURL)
let toolBin = ''
if (process.platform === 'win32') {
const toolExtractedFolder: string = await tc.extractZip(toolAssets, tempDir)
toolBin = `${toolExtractedFolder}/${HugoTool.CmdName}.exe`
} else {
const toolExtractedFolder: string = await tc.extractTar(toolAssets, tempDir)
toolBin = `${toolExtractedFolder}/${HugoTool.CmdName}`
}
await io.mv(toolBin, binDir)
}

19
src/constants.ts Normal file
View file

@ -0,0 +1,19 @@
export enum Hugo {
Name = 'Hugo',
Org = 'gohugoio',
Repo = 'hugo',
CmdName = 'hugo',
CmdOptVersion = 'version',
TestVersionLatest = '0.83.1',
TestVersionSpec = '0.82.1'
}
export enum DartSass {
Org = 'sass',
Repo = 'dart-sass'
}
export enum Action {
WorkDirName = 'actions_hugo',
TempDirName = '_temp'
}

90
src/dart-sass.ts Normal file
View file

@ -0,0 +1,90 @@
import { IGithubRelease, IReleaseLookup } from './asset-lookup'
import { DartSass } from './constants'
import { components } from '@octokit/openapi-types'
import * as core from '@actions/core'
import { Platform } from './os'
import { downloadTool } from '@actions/tool-cache'
export interface IDartSassInstallCommand {
version: string
}
export class DartSassInstaller {
private readonly releaseLookup: IReleaseLookup
private readonly platform: Platform
constructor(releaseLookup: IReleaseLookup) {
this.platform = new Platform()
this.releaseLookup = releaseLookup
}
async install(cmd: IDartSassInstallCommand): Promise<void> {
const release = await this.releaseLookup.getRelease(
DartSass.Org,
DartSass.Repo,
cmd.version,
DartSassReleaseTransformer
)
core.debug(`Operating System: ${this.platform.os}`)
core.debug(`Processor Architecture: ${this.platform.arch}`)
const workDir = await this.platform.createWorkDir()
const binDir = await this.platform.createBinDir(workDir)
const tempDir = await this.platform.createTempDir(workDir)
const toolUrl = release.assetUrl(this.platform)
if (!toolUrl) {
throw new Error('No matching URL detected for given platform')
}
await downloadTool(toolUrl, binDir, tempDir)
}
}
export const DartSassReleaseTransformer = {
map(release: components['schemas']['release']): DartSassRelease {
return new DartSassRelease(
release.tag_name.replace('v', ''),
release.assets
)
}
}
export class DartSassRelease implements IGithubRelease {
private static readonly keyReplacementRegex = new RegExp(
'dart-sass-*(\\d+.\\d+.\\d+)-'
)
private static readonly platformMapping: { [index: string]: string } = {
linux: 'linux',
win32: 'windows',
darwin: 'macos'
}
private readonly assets: Map<string, string>
readonly tag_name: string
constructor(
tag_name: string,
assets: components['schemas']['release']['assets']
) {
this.tag_name = tag_name
this.assets = new Map<string, string>()
assets.forEach(asset => {
this.assets.set(
asset.name.replace(DartSassRelease.keyReplacementRegex, ''),
asset.url
)
})
}
assetUrl(platform: Platform): string | undefined {
const mappedOS = DartSassRelease.platformMapping[platform.os]
return this.assets.get(
`${mappedOS}-${platform.arch}${platform.archiveExtension()}`
)
}
}

94
src/hugo.ts Normal file
View file

@ -0,0 +1,94 @@
import * as core from '@actions/core'
import { Hugo } from './constants'
import { IGithubRelease, IReleaseLookup } from './asset-lookup'
import { Platform } from './os'
import { components } from '@octokit/openapi-types'
import { downloadTool } from '@actions/tool-cache'
export interface IHugoInstallCommand {
version: string
extended: boolean
}
export class HugoInstaller {
private readonly releaseLookup: IReleaseLookup
private readonly platform: Platform
constructor(releaseLookup: IReleaseLookup) {
this.platform = new Platform()
this.releaseLookup = releaseLookup
}
async install(cmd: IHugoInstallCommand): Promise<void> {
const release = await this.releaseLookup.getRelease(
Hugo.Org,
Hugo.Repo,
cmd.version,
HugoReleaseTransformer
)
core.debug(`Hugo extended: ${cmd.extended}`)
core.debug(`Operating System: ${this.platform.os}`)
core.debug(`Processor Architecture: ${this.platform.arch}`)
const workDir = await this.platform.createWorkDir()
const binDir = await this.platform.createBinDir(workDir)
const tempDir = await this.platform.createTempDir(workDir)
const toolUrl = release.assetUrl(this.platform, cmd.extended)
if (!toolUrl) {
throw new Error('No matching URL detected for given platform')
}
await downloadTool(toolUrl, binDir, tempDir)
}
}
export const HugoReleaseTransformer = {
map(release: components['schemas']['release']): HugoRelease {
return new HugoRelease(release.tag_name.replace('v', ''), release.assets)
}
}
export class HugoRelease implements IGithubRelease {
private static readonly keyReplacementRegex = new RegExp(
'hugo_(extended_)*(\\d+.\\d+.\\d+)_'
)
readonly tag_name: string
private readonly defaultAssets: Map<string, string>
private readonly extendedAssets: Map<string, string>
constructor(
tag_name: string,
assets: components['schemas']['release']['assets']
) {
this.tag_name = tag_name
this.defaultAssets = new Map<string, string>()
this.extendedAssets = new Map<string, string>()
assets.forEach(asset => {
if (asset.name.includes('extended')) {
this.extendedAssets.set(
asset.name.replace(HugoRelease.keyReplacementRegex, ''),
asset.url
)
} else {
this.defaultAssets.set(
asset.name.replace(HugoRelease.keyReplacementRegex, ''),
asset.url
)
}
})
}
assetUrl(platform: Platform, extended: boolean): string | undefined {
const src = extended ? this.extendedAssets : this.defaultAssets
const arch = platform.os === 'darwin' ? 'universal' : platform.arch
const key = `${platform.os}-${arch}${platform.archiveExtension()}`
return src.get(key)
}
}

9
src/index.ts Normal file
View file

@ -0,0 +1,9 @@
import * as core from '@actions/core'
import * as main from './main'
;(async (): Promise<void> => {
try {
await main.run()
} catch (e: any) {
core.setFailed(`Action failed with error ${e.message}`)
}
})()

23
src/main.ts Normal file
View file

@ -0,0 +1,23 @@
import * as core from '@actions/core'
import { HugoInstaller } from './hugo'
import { IReleaseLookup, OctokitReleaseLookup } from './asset-lookup'
import { DartSassInstaller } from './dart-sass'
export async function run(): Promise<void> {
const releaseLookup: IReleaseLookup = new OctokitReleaseLookup(
core.getInput('github-token')
)
const hugoInstaller = new HugoInstaller(releaseLookup)
await hugoInstaller.install({
version: core.getInput('hugo-version'),
extended: core.getBooleanInput('extended')
})
if (!core.getBooleanInput('dart-sass')) return
const dartSassInstaller = new DartSassInstaller(releaseLookup)
await dartSassInstaller.install({
version: core.getInput('dart-sass-version')
})
}

65
src/os.ts Normal file
View file

@ -0,0 +1,65 @@
import * as process from 'node:process'
import path from 'path'
import { Action } from './constants'
import * as io from '@actions/io'
import * as core from '@actions/core'
interface Env {
[key: string]: string | undefined
}
export class Platform {
os: string
arch: string
env: Env
constructor(
os: string = process.platform,
arch: string = process.arch,
env: Env = process.env
) {
this.os = os
this.arch = arch
this.env = env
}
archiveExtension(): string {
if (this.os === 'win32') {
return '.zip'
}
return '.tar.gz'
}
async createWorkDir(): Promise<string> {
const workDir = path.join(this.getHomeDir(), Action.WorkDirName)
await io.mkdirP(workDir)
core.debug(`workDir: ${workDir}`)
return workDir
}
async createTempDir(workDir: string): Promise<string> {
const tempDir = path.join(workDir, Action.TempDirName)
await io.mkdirP(tempDir)
core.debug(`tempDir: ${tempDir}`)
return tempDir
}
async createBinDir(workDir: string): Promise<string> {
const binDir = path.join(workDir, 'bin')
await io.mkdirP(binDir)
core.addPath(binDir)
core.debug(`binDir: ${binDir}`)
return binDir
}
getHomeDir(): string {
const homedir =
this.os === 'win32'
? this.env['USERPROFILE'] || 'C:\\'
: this.env.HOME || '/root'
core.debug(`homeDir: ${homedir}`)
return homedir
}
}

18
tsconfig.json Normal file
View file

@ -0,0 +1,18 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"target": "ES2022",
"rootDir": "./src",
"moduleResolution": "Node",
"baseUrl": "./",
"sourceMap": true,
"outDir": "./dist",
"noImplicitAny": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"newLine": "lf"
},
"exclude": ["./dist", "./node_modules", "./__tests__", "./coverage"]
}