Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: 'Upload a Build Artifact to Nextcloud'
description: 'Upload a build artifact to Nextcloud that can be used by subsequent workflow steps'
author: 'Trym Lund Flogard'
inputs:
inputs:
name:
description: 'Artifact name'
default: 'artifact'
Expand All @@ -17,6 +17,10 @@ inputs:
nextcloud-password:
description: 'The password for the nextcloud user'
required: true
no-zip:
description: 'Whether to zip files. Incompatible with uploading multiple files.'
default: false
required: false
if-no-files-found:
description: >
The desired behavior if no files are found using the provided path.
Expand Down
73 changes: 53 additions & 20 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ require('./sourcemap-register.js');/******/ (() => { // webpackBootstrap

var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
Expand Down Expand Up @@ -49,6 +53,9 @@ class ActionInputs {
get Token() {
return core.getInput('token', { required: true });
}
get NoZip() {
return Boolean(core.getInput('no-zip', { required: false }));
}
get NoFileBehvaior() {
const notFoundAction = core.getInput('if-no-files-found', { required: false }) || NoFileOption_1.NoFileOption.warn;
const noFileBehavior = NoFileOption_1.NoFileOption[notFoundAction];
Expand All @@ -70,7 +77,11 @@ exports.ActionInputs = ActionInputs;

var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
Expand All @@ -94,7 +105,7 @@ const fs_1 = __nccwpck_require__(7147);
const core_1 = __nccwpck_require__(3722);
const path = __importStar(__nccwpck_require__(1017));
const util_1 = __nccwpck_require__(3837);
const stats = util_1.promisify(fs_1.stat);
const stats = (0, util_1.promisify)(fs_1.stat);
class FileFinder {
constructor(searchPath, globOptions) {
this.searchPath = searchPath;
Expand All @@ -117,26 +128,26 @@ class FileFinder {
const fileStats = await stats(searchResult);
// isDirectory() returns false for symlinks if using fs.lstat(), make sure to use fs.stat() instead
if (!fileStats.isDirectory()) {
core_1.debug(`File:${searchResult} was found using the provided searchPath`);
(0, core_1.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())) {
core_1.info(`Uploads are case insensitive: ${searchResult} was detected that it will be overwritten by another file with the same path`);
(0, core_1.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 {
core_1.debug(`Removing ${searchResult} from rawSearchResults because it is a directory`);
(0, core_1.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 = globber.getSearchPaths();
if (searchPaths.length > 1) {
core_1.info(`Multiple search paths detected. Calculating the least common ancestor of all paths`);
(0, core_1.info)(`Multiple search paths detected. Calculating the least common ancestor of all paths`);
const lcaSearchPath = this.getMultiPathLCA(searchPaths);
core_1.info(`The least common ancestor is ${lcaSearchPath}. This will be the root directory of the artifact`);
(0, core_1.info)(`The least common ancestor is ${lcaSearchPath}. This will be the root directory of the artifact`);
return {
filesToUpload: searchResults,
rootDirectory: lcaSearchPath
Expand Down Expand Up @@ -166,7 +177,7 @@ class FileFinder {
let smallestPathLength = Number.MAX_SAFE_INTEGER;
// split each of the search paths using the platform specific separator
for (const searchPath of searchPaths) {
core_1.debug(`Using search path ${searchPath}`);
(0, core_1.debug)(`Using search path ${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);
Expand Down Expand Up @@ -243,7 +254,11 @@ var NoFileOption;

var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
Expand Down Expand Up @@ -286,7 +301,11 @@ run();

var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
Expand Down Expand Up @@ -364,10 +383,11 @@ class NextcloudArtifact {
},
...github.context.repo
});
const client = new NextcloudClient_1.NextcloudClient(this.inputs.Endpoint, this.name, files.rootDirectory, this.inputs.Username, this.inputs.Password);
const client = new NextcloudClient_1.NextcloudClient(this.inputs.Endpoint, this.name, files.rootDirectory, this.inputs.Username, this.inputs.Password, this.inputs.NoZip);
try {
const shareableUrl = await client.uploadFiles(files.filesToUpload);
core.setOutput('SHAREABLE_URL', shareableUrl);
core.setOutput('DIRECT_SHAREABLE_URL', `${shareableUrl}/download`);
core.info(`Nextcloud shareable URL: ${shareableUrl}`);
const resp = await this.octokit.rest.checks.update({
check_run_id: createResp.data.id,
Expand Down Expand Up @@ -445,7 +465,11 @@ exports.NextcloudArtifact = NextcloudArtifact;

var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
Expand Down Expand Up @@ -477,13 +501,14 @@ const uuid_1 = __nccwpck_require__(5650);
const webdav = __importStar(__nccwpck_require__(4561));
const fs = fsSync.promises;
class NextcloudClient {
constructor(endpoint, artifact, rootDirectory, username, password) {
constructor(endpoint, artifact, rootDirectory, username, password, nozip) {
this.endpoint = endpoint;
this.artifact = artifact;
this.rootDirectory = rootDirectory;
this.username = username;
this.password = password;
this.guid = uuid_1.v4();
this.nozip = nozip;
this.guid = (0, uuid_1.v4)();
this.headers = { Authorization: 'Basic ' + Buffer.from(`${this.username}:${this.password}`).toString('base64') };
this.davClient = webdav.createClient(`${this.endpoint.href}remote.php/dav/files/${this.username}`, {
username: this.username,
Expand All @@ -494,8 +519,16 @@ class NextcloudClient {
async uploadFiles(files) {
core.info('Preparing upload...');
const spec = this.uploadSpec(files);
core.info('Zipping files...');
const zip = await this.zipFiles(spec);
let zip;
if (this.nozip) {
if (spec.length > 1)
throw Error('no-zip is incompatible with multiple file uploads.');
zip = spec[0].absolutePath;
}
else {
core.info('Zipping files...');
zip = await this.zipFiles(spec);
}
try {
core.info('Uploading to Nextcloud...');
const filePath = await this.upload(zip);
Expand Down Expand Up @@ -570,9 +603,9 @@ class NextcloudClient {
if (!(await this.davClient.exists(remoteFileDir))) {
await this.davClient.createDirectory(remoteFileDir, { recursive: true });
}
const remoteFilePath = `${remoteFileDir}/${this.artifact}.zip`;
const remoteFilePath = `${remoteFileDir}/${this.artifact}${this.nozip ? '' : '.zip'}`;
core.debug(`Transferring file... (${file})`);
await this.davClient.putFileContents(remoteFilePath, await fs.readFile(file));
await this.davClient.putFileContents(remoteFilePath, fsSync.createReadStream(file));
return remoteFilePath;
}
async shareFile(remoteFilePath) {
Expand All @@ -583,7 +616,7 @@ class NextcloudClient {
publicUpload: 'false',
permissions: 1
};
const res = await node_fetch_1.default(url, {
const res = await (0, node_fetch_1.default)(url, {
method: 'POST',
headers: Object.assign(this.headers, {
'OCS-APIRequest': true,
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/ActionInputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export class ActionInputs implements Inputs {
return core.getInput('token', { required: true })
}

get NoZip(): boolean {
return Boolean(core.getInput('no-zip', { required: false }))
}

get NoFileBehvaior(): NoFileOption {
const notFoundAction = core.getInput('if-no-files-found', { required: false }) || NoFileOption.warn
const noFileBehavior: NoFileOption = NoFileOption[notFoundAction as keyof typeof NoFileOption]
Expand Down
2 changes: 2 additions & 0 deletions src/Inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ export interface Inputs {
readonly Token: string

readonly NoFileBehvaior: NoFileOption

readonly NoZip: boolean
}
4 changes: 3 additions & 1 deletion src/nextcloud/NextcloudArtifact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,14 @@ export class NextcloudArtifact {
this.name,
files.rootDirectory,
this.inputs.Username,
this.inputs.Password
this.inputs.Password,
this.inputs.NoZip
)

try {
const shareableUrl = await client.uploadFiles(files.filesToUpload)
core.setOutput('SHAREABLE_URL', shareableUrl)
core.setOutput('DIRECT_SHAREABLE_URL', `${shareableUrl}/download`)
core.info(`Nextcloud shareable URL: ${shareableUrl}`)
const resp = await this.octokit.rest.checks.update({
check_run_id: createResp.data.id,
Expand Down
23 changes: 16 additions & 7 deletions src/nextcloud/NextcloudClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import * as core from '@actions/core'
import * as os from 'os'
import * as archiver from 'archiver'
import fetch, { HeadersInit } from 'node-fetch'
import btoa from 'btoa'
import { v4 as uuidv4 } from 'uuid'
import * as webdav from 'webdav'
import { URL } from 'url'
Expand All @@ -26,7 +25,8 @@ export class NextcloudClient {
private artifact: string,
private rootDirectory: string,
private username: string,
private password: string
private password: string,
private nozip: boolean
) {
this.guid = uuidv4()
this.headers = { Authorization: 'Basic ' + Buffer.from(`${this.username}:${this.password}`).toString('base64') }
Expand All @@ -40,15 +40,24 @@ export class NextcloudClient {
async uploadFiles(files: string[]): Promise<string> {
core.info('Preparing upload...')
const spec = this.uploadSpec(files)
core.info('Zipping files...')
const zip = await this.zipFiles(spec)
let zip

if (this.nozip) {
if (spec.length > 1) throw Error('no-zip is incompatible with multiple file uploads.')
zip = spec[0].absolutePath
} else {
core.info('Zipping files...')
zip = await this.zipFiles(spec)
}

try {
core.info('Uploading to Nextcloud...')
const filePath = await this.upload(zip)
core.info(`Remote file path: ${filePath}`)
return await this.shareFile(filePath)
} finally {
await fs.unlink(zip)
// Don't delete user-made files
if (!this.nozip) await fs.unlink(zip)
}
}

Expand Down Expand Up @@ -126,10 +135,10 @@ export class NextcloudClient {
await this.davClient.createDirectory(remoteFileDir, { recursive: true })
}

const remoteFilePath = `${remoteFileDir}/${this.artifact}.zip`
const remoteFilePath = `${remoteFileDir}/${this.artifact}${this.nozip ? '' : '.zip'}`
core.debug(`Transferring file... (${file})`)

await this.davClient.putFileContents(remoteFilePath, await fs.readFile(file))
await this.davClient.putFileContents(remoteFilePath, fsSync.createReadStream(file))

return remoteFilePath
}
Expand Down