Update to the latest async-neocities 4.0

BREAKING CHANGE: api_token action input is renamed to api_key, please update this

BREAKING CHANGE: added a required neocities_supporter action input to toggle unsupported file filtering

BREAKING CHANGE: addad a preview_before_deploy action input to toggle informational deploy plans prior to deploys

BREAKING CHANGE: completely rewrote the underlying library to provide better error handling and reporting

BREAKING CHANGE: Remove a bunch of real time stats and progress meters. Deploys were finishing in seconds and these were very complicated to maintain.
This commit is contained in:
Bret Comnes 2024-11-19 17:06:33 -08:00
parent f9a550fd47
commit 7b14798c89
No known key found for this signature in database
GPG Key ID: 3705F4634DC3A1AC
13 changed files with 29175 additions and 11183 deletions

View File

@ -5,7 +5,7 @@ on:
push: push:
branches: branches:
- master - master
env: env:
FORCE_COLOR: 1 FORCE_COLOR: 1
node_version: lts/* node_version: lts/*
@ -32,7 +32,9 @@ jobs:
- name: Deploy to neocities - name: Deploy to neocities
uses: bcomnes/deploy-to-neocities@master # dont use master in production uses: bcomnes/deploy-to-neocities@master # dont use master in production
with: with:
api_token: ${{ secrets.NEOCITIES_API_TOKEN }} api_key: ${{ secrets.NEOCITIES_API_TOKEN }}
cleanup: true cleanup: true
dist_dir: public dist_dir: public
protected_files: 'dropbox/*' protected_files: 'dropbox/*'
neocities_supporter: true # set this to true if you have a supporter account and want to bypass unsuported files filter.
preview_before_deploy: true

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ public
node_modules node_modules
tmp_modules tmp_modules
package-lock.json package-lock.json
coverage

View File

@ -10,6 +10,8 @@
Efficiently deploy a website to [Neocities][nc] using [Github actions](https://github.com/features/actions). Uses content aware diffing to only update files that changed. Efficiently deploy a website to [Neocities][nc] using [Github actions](https://github.com/features/actions). Uses content aware diffing to only update files that changed.
Alternatively, you can use the bin helper in [async-neocities](https://github.com/bcomnes/async-neocities) to deploy to neocities locally from your own machine as well as in CI.
## Usage ## Usage
```yaml ```yaml
@ -30,23 +32,26 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
# Set up any tools and build steps here # Set up any tools and build steps here
# This example uses a Node.js toolchain to build a site # This example uses a Node.js toolchain to build a site
- name: Use Node.js - name: Use Node.js
uses: actions/setup-node@v3 uses: actions/setup-node@v4
with: with:
node-version: lts/* node-version: lts/*
# If you have a different build process, replace this with your own build steps
- name: Install deps and build - name: Install deps and build
run: | run: |
npm i npm i
npm run build npm run build
# When the dist_dir is ready, deploy it to neocities # When the dist_dir is ready, deploy it to neocities
- name: Deploy to neocities - name: Deploy to neocities
uses: bcomnes/deploy-to-neocities@v2 uses: bcomnes/deploy-to-neocities@v3
with: with:
api_token: ${{ secrets.NEOCITIES_API_TOKEN }} api_key: ${{ secrets.NEOCITIES_API_TOKEN }}
cleanup: false cleanup: false
neocities_supporter: false # set this to true if you have a supporter account and want to bypass unsuported files filter.
preview_before_deploy: true # print a deployment plan prior to waiting for files to upload.
dist_dir: public dist_dir: public
``` ```
@ -73,7 +78,9 @@ You most likely only want to run this on the `master` branch so that only change
- `api_token` (**REQUIRED**): The API token for your [Neocities][nc] website to deploy to. - `api_token` (**REQUIRED**): The API token for your [Neocities][nc] website to deploy to.
- `dist_dir`: The directory to deploy to [Neocities][nc]. Default: `public`. Don't deploy your root repo directory (e.g. `./`). It contains `.git`, `.github` and other files that won't deploy properly to neocities. Keep it clean by keeping or building your site into a subdir and deploy that. - `dist_dir`: The directory to deploy to [Neocities][nc]. Default: `public`. Don't deploy your root repo directory (e.g. `./`). It contains `.git`, `.github` and other files that won't deploy properly to neocities. Keep it clean by keeping or building your site into a subdir and deploy that.
- `neocoties_supporter`: Set this to `true` if you have a paid neocities account and want to bypass the [unsupported files filter](https://neocities.org/site_files/allowed_types).
- `cleanup`: Boolean string (`true` or `false`). If `true`, `deploy-to-neocities` will destructively delete files found on [Neocities][nc] not found in your `dist_dir`. Default: `false`. - `cleanup`: Boolean string (`true` or `false`). If `true`, `deploy-to-neocities` will destructively delete files found on [Neocities][nc] not found in your `dist_dir`. Default: `false`.
- `preview_before_deploy`: Boolean string (`true` or `false`). If `true`, `deploy-to-neocities` will print a preview of the files that will be uploaded and deleted. Default: `true`.
- `protected_files`: An optional glob string used to mark files as protected. Protected files are never cleaned up. Test this option out with `cleanup` set to false before relying on it. Protected files are printed when `cleanup` is set to true or false. Glob strings are processed by [minimatch](https://github.com/isaacs/minimatch) against remote neocities file paths. Protected files can still be updated. - `protected_files`: An optional glob string used to mark files as protected. Protected files are never cleaned up. Test this option out with `cleanup` set to false before relying on it. Protected files are printed when `cleanup` is set to true or false. Glob strings are processed by [minimatch](https://github.com/isaacs/minimatch) against remote neocities file paths. Protected files can still be updated.
### Outputs ### Outputs

View File

@ -4,20 +4,32 @@ branding:
icon: aperture icon: aperture
color: orange color: orange
inputs: inputs:
api_token: # api token for site to deploy to api_key: # api token for site to deploy to
description: 'Neocities API token for site to deploy to' description: 'Neocities API key for site to deploy to'
required: true required: true
dist_dir: dist_dir:
description: 'Local folder to deploy to neocities' description: 'Local folder to deploy to neocities'
default: 'public' default: 'public'
required: true required: true
neocities_supporter:
description: 'Set to true if you are a Neocities supporter to bypass file type upload restrictions'
default: 'false'
required: true
cleanup: cleanup:
description: Delete orphaned files on neocities that don't exist in distDir description: Delete orphaned files on neocities that don't exist in distDir
default: false default: 'false'
required: true required: true
preview_before_deploy:
description: 'Set to true if you want to print deploy preview stats prior to deploying.'
default: 'true'
required: false
protected_files: protected_files:
description: A glob string that prevents matched files from ever being deleted. description: A glob string that prevents matched files from ever being deleted.
required: false required: false
api_token: # api token for site to deploy to
description: 'Neocities API key for site to deploy to'
required: false
deprecationMessage: 'api_token is deprecated, use api_key instead'
runs: runs:
using: 'node20' using: 'node20'
main: 'dist/index.js' main: 'dist/index.cjs'

File diff suppressed because one or more lines are too long

7
dist/index.cjs.map vendored Normal file

File diff suppressed because one or more lines are too long

7
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

8237
dist/meta.json vendored Normal file

File diff suppressed because it is too large Load Diff

8
eslint.config.js Normal file
View File

@ -0,0 +1,8 @@
import neostandard, { resolveIgnoresFromGitignore } from 'neostandard'
export default neostandard({
ignores: [
...resolveIgnoresFromGitignore(),
'dist'
],
})

113
index.js
View File

@ -1,57 +1,84 @@
const core = require('@actions/core') import core from '@actions/core'
// const github = require('@actions/github') import {
const Neocities = require('async-neocities') NeocitiesAPIClient,
const path = require('path') printDeployText,
const ms = require('ms') printPreviewText,
const assert = require('webassert').default printResultsErrorDump,
const fsp = require('fs').promises SimpleTimer
const { minimatch } = require('minimatch') } from 'async-neocities'
const { stackWithCauses } = require('pony-cause') import path from 'node:path'
import assert from 'node:assert'
import fs from 'node:fs/promises'
import { minimatch } from 'minimatch'
let cleanup async function run () {
const key = core.getInput('api_key') || core.getInput('api_token')
async function doDeploy () {
const token = core.getInput('api_token')
const distDir = path.join(process.cwd(), core.getInput('dist_dir')) const distDir = path.join(process.cwd(), core.getInput('dist_dir'))
cleanup = JSON.parse(core.getInput('cleanup')) const cleanup = JSON.parse(core.getInput('cleanup'))
const neocitiesSupporter = JSON.parse(core.getInput('neocities_supporter'))
const previewDeploy = JSON.parse(core.getInput('preview_before_deploy'))
const protectedFilesGlob = core.getInput('protected_files') const protectedFilesGlob = core.getInput('protected_files')
assert(typeof cleanup === 'boolean', 'Cleanup input must be a boolean "true" or "false"') assert(typeof cleanup === 'boolean', '`cleanup` input must be a boolean "true" or "false"')
const stat = await fsp.stat(distDir) assert(typeof neocitiesSupporter === 'boolean', '`neocities_supporter` input must be a boolean "true" or "false"')
assert(stat.isDirectory(), 'dist_dir must be a directory that exists') assert(typeof previewDeploy === 'boolean', '`preview_before_deploy` input must be a boolean "true" or "false"')
const client = new Neocities(token) const stat = await fs.stat(distDir)
const deployOpts = { assert(stat.isDirectory(), '`dist_dir` input must be a path to a directory that exists')
cleanup,
statsCb: Neocities.statsHandler() const client = new NeocitiesAPIClient(key)
if (previewDeploy) {
const previewTimer = new SimpleTimer()
console.log('Running deploy preview prior to deployment...\n\n')
const diff = await client.previewDeploy({
directory: distDir,
includeUnsupportedFiles: neocitiesSupporter,
protectedFileFilter: protectedFilesGlob ? minimatch.filter(protectedFilesGlob) : undefined
})
previewTimer.stop()
printPreviewText({
diff,
timer: previewTimer,
cleanup,
includeUnsupportedFiles: neocitiesSupporter
})
} }
if (protectedFilesGlob) deployOpts.protectedFileFilter = minimatch.filter(protectedFilesGlob) const deployTimer = new SimpleTimer()
console.log('Deploying to Neocities...')
const stats = await client.deploy(distDir, deployOpts) const results = await client.deploy({
directory: distDir,
cleanup,
includeUnsupportedFiles: neocitiesSupporter,
protectedFileFilter: protectedFilesGlob ? minimatch.filter(protectedFilesGlob) : undefined
})
console.log(`Deployed to Neocities in ${ms(stats.time)}:`) deployTimer.stop()
console.log(` Uploaded ${stats.filesToUpload.length} files`)
console.log(` ${cleanup ? 'Deleted' : 'Orphaned'} ${stats.filesToDelete.length} files`) if (results.errors.length > 0) {
console.log(` Skipped ${stats.filesSkipped.length} files`) printResultsErrorDump({
console.log(` ${stats.protectedFiles.length} protected files:`) results,
if (stats.protectedFiles.length) { timer: deployTimer
console.log(stats.protectedFiles) })
core.setFailed('The deploy completed with errors.')
} else {
printDeployText({
results,
timer: deployTimer,
cleanup,
includeUnsupportedFiles: neocitiesSupporter
})
} }
} }
doDeploy().catch(err => { run().catch(err => {
console.error(stackWithCauses(err)) console.log('Unexpected error/throw during deployment:\n\n')
if (err.stats) { console.dir(err, { colors: true, depth: 999 })
console.log('Files to upload: ') core.setFailed(err instanceof Error ? err.message : `An unexpected error occurred during deployment: ${err}`)
console.dir(err.stats.filesToUpload, { colors: true, depth: 999 })
if (cleanup) {
console.log('Files to delete: ')
console.dir(err.stats.filesToDelete, { colors: true, depth: 999 })
}
}
core.setFailed(err.message)
}) })

View File

@ -8,25 +8,25 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": "1.11.1", "@actions/core": "1.11.1",
"async-neocities": "2.1.6", "async-neocities": "4.0.3",
"minimatch": "10.0.1", "minimatch": "10.0.1"
"ms": "2.1.3",
"pony-cause": "^2.1.4",
"webassert": "3.0.2"
}, },
"devDependencies": { "devDependencies": {
"@voxpelli/tsconfig": "^15.0.0",
"top-bun": "^10.0.0", "top-bun": "^10.0.0",
"auto-changelog": "^2.0.0", "auto-changelog": "^2.0.0",
"dependency-check": "^4.1.0",
"gh-release": "^7.0.0", "gh-release": "^7.0.0",
"npm-run-all2": "^7.0.1", "npm-run-all2": "^7.0.0",
"standard": "^17.0.0", "neostandard": "^0.11.8",
"esbuild": "^0.24.0" "c8": "^10.0.0",
"esbuild": "~0.24.0",
"typescript": "~5.6.2"
}, },
"homepage": "https://github.com/bcomnes/deploy-to-neocities#readme", "homepage": "https://github.com/bcomnes/deploy-to-neocities#readme",
"keywords": [], "keywords": [],
"license": "MIT", "license": "MIT",
"main": "index.js", "main": "index.js",
"type": "module",
"private": true, "private": true,
"repository": { "repository": {
"type": "git", "type": "git",
@ -34,23 +34,20 @@
}, },
"scripts": { "scripts": {
"build": "npm run clean && run-p build:*", "build": "npm run clean && run-p build:*",
"build:action": "rm -rf dist && esbuild index.js --bundle --platform=node --target=node16 --sourcemap=external --outdir=dist", "build:action": "rm -rf dist && esbuild index.js --bundle --platform=node --sourcemap=external --outdir=dist --metafile=dist/meta.json --out-extension:.js=.cjs",
"build:site": "tb --src . --dest public", "build:site": "tb --src . --dest public --ignore dist,coverage",
"dist-pkg": "echo \"{ \\\"type\\\": \\\"commonjs\\\" }\" > dist/package.json",
"clean": "rm -rf public && mkdir -p public", "clean": "rm -rf public && mkdir -p public",
"release": "git push --follow-tags && gh-release -y", "release": "git push --follow-tags && gh-release -y",
"start": "npm run watch", "start": "npm run watch",
"test": "run-s test:*", "test": "run-s test:*",
"test:deps": "dependency-check . --no-dev --no-peer", "test:lint": "eslint",
"test:standard": "standard", "test:tsc": "tsc",
"test:node": "c8 node --test",
"version": "run-s version:*", "version": "run-s version:*",
"version:build": "npm run build:action && git add dist", "version:build": "npm run build:action && git add dist",
"version:changelog": "auto-changelog -p --template keepachangelog auto-changelog --breaking-pattern 'BREAKING CHANGE:' && git add CHANGELOG.md", "version:changelog": "auto-changelog -p --template keepachangelog auto-changelog --breaking-pattern 'BREAKING CHANGE:' && git add CHANGELOG.md",
"watch": "npm run clean && run-p watch:*", "watch": "npm run clean && run-p watch:*",
"watch:site": "npm run build:site -- -w" "watch:site": "npm run build:site -- -w"
},
"standard": {
"ignore": [
"dist"
]
} }
} }

View File

@ -1,5 +1,6 @@
const tap = require('tap') import assert from 'node:assert'
import test from 'node:test'
tap.test('test', async t => { test('test', async _t => {
t.ok(true) assert.ok(true)
}) })

14
tsconfig.json Normal file
View File

@ -0,0 +1,14 @@
{
"extends": "@voxpelli/tsconfig/node20.json",
"compilerOptions": {
"skipLibCheck": true
},
"include": [
"**/*"
],
"exclude": [
"node_modules",
"public",
"dist"
]
}