Skip to content

Commit

Permalink
Use cache instead of artifacts
Browse files Browse the repository at this point in the history
  • Loading branch information
dsame committed Jun 25, 2023
1 parent c7d4376 commit 6148637
Show file tree
Hide file tree
Showing 7 changed files with 10,589 additions and 62,969 deletions.
73,379 changes: 10,432 additions & 62,947 deletions dist/index.js

Large diffs are not rendered by default.

114 changes: 114 additions & 0 deletions src/classes/http-client/HttpClient.ts
@@ -0,0 +1,114 @@
import * as core from '@actions/core';
import {getOctokit} from '@actions/github';
import {retry} from '@octokit/plugin-retry';
import fs from 'fs';

const getCacheApiUrl = (): string => {
const baseUrl: string = process.env['ACTIONS_CACHE_URL'] || '';
if (!baseUrl) {
throw new Error('Cache Service Url not found, unable to restore cache.');
}

const url = `${baseUrl}_apis/artifactcache/caches`;
core.debug(`Resource Url: ${url}`);
return url;
};

const getRequestOptions = (
options?: Record<string, any>
): Record<string, any> => ({
headers: {'X-GitHub-Api-Version': '2022-11-28', ...options}
});

export const uploadFile = async (
filePath: string,
repoToken: string,
key: string,
version: string
): Promise<void> => {
const resourceUrl = getCacheApiUrl();
const client = getOctokit(repoToken, undefined, retry);
/*
const fd = fs.openSync(filePath, 'r')
const additionalHeaders = {
// 'Content-Type': 'application/octet-stream',
'X-GitHub-Api-Version': '2022-11-28',
// 'Content-Range': `bytes 0-${size}/*`
}*/
/*
try {
core.debug('Removing existing state');
await client.request(
`DELETE ${resourceUrl}?key=${key}`,
getRequestOptions()
);
core.debug('Existing state removed');
} catch (error) {
if (error.response.status === 404) {
core.debug('No state exists');
} else {
core.warning(`Eroro: ${error.response.status} ${error.message}`);
}
}
*/
let responseReserve;
try {
core.info('Store current state');
core.debug('Reserve cache');
const cacheSize = fs.statSync(filePath).size;

const data = {
key,
version,
cacheSize
};

const dataSerialized = JSON.stringify(data, null, 2);

const responseReserve = await client.request(
`POST ${resourceUrl}`,
getRequestOptions({
headers: {
accept: 'application/json',
'content-type': 'application/json'
},
data: dataSerialized
//...data
})
);

/*
responseReserve = fetch(resourceUrl, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: dataSerialized
});
*/
core.debug(
`========> reserve response: ${JSON.stringify(responseReserve)}`
);
} catch (error) {
console.log({error});

Check failure on line 95 in src/classes/http-client/HttpClient.ts

View workflow job for this annotation

GitHub Actions / Basic validation / build (ubuntu-latest)

Unexpected console statement

Check failure on line 95 in src/classes/http-client/HttpClient.ts

View workflow job for this annotation

GitHub Actions / Basic validation / build (windows-latest)

Unexpected console statement

Check failure on line 95 in src/classes/http-client/HttpClient.ts

View workflow job for this annotation

GitHub Actions / Basic validation / build (macos-latest)

Unexpected console statement
core.debug(`========> reserve error: ${JSON.stringify(error)}`);
core.debug(
`========> reserve error response: ${JSON.stringify(responseReserve)}`
);
}

/*
const uploadChunkResponse = await retryHttpClientResponse(
`uploadChunk (start: ${start}, end: ${end})`,
async () =>
httpClient.sendStream(
'PATCH',
resourceUrl,
openStream(),
additionalHeaders
)
)
*/
};
2 changes: 1 addition & 1 deletion src/classes/issue.ts
Expand Up @@ -27,7 +27,7 @@ export class Issue implements IIssue {

constructor(
options: Readonly<IIssuesProcessorOptions>,
issue: Readonly<OctokitIssue> | Readonly<IIssue>
issue: Readonly<OctokitIssue> // | Readonly<IIssue>
) {
this._options = options;
this.title = issue.title;
Expand Down
8 changes: 5 additions & 3 deletions src/classes/issues-processor.ts
Expand Up @@ -574,9 +574,11 @@ export class IssuesProcessor {
});
this.statistics?.incrementFetchedItemsCount(issueResult.data.length);

return issueResult.data.map(
(issue: Readonly<OctokitIssue>): Issue => new Issue(this.options, issue)
);
// state_reason is incompatible - oktokit dependency conflict?
// return issueResult.data.map((issue: Readonly<OctokitIssue>): Issue => {
return issueResult.data.map((issue): Issue => {
return new Issue(this.options, issue as Readonly<OctokitIssue>);
});
} catch (error) {
throw Error(`Getting issues was blocked by the error: ${error.message}`);
}
Expand Down
48 changes: 33 additions & 15 deletions src/classes/state.ts
Expand Up @@ -4,20 +4,22 @@ import os from 'os';
import crypto from 'crypto';

Check warning on line 4 in src/classes/state.ts

View workflow job for this annotation

GitHub Actions / Basic validation / build (ubuntu-latest)

'crypto' is defined but never used

Check warning on line 4 in src/classes/state.ts

View workflow job for this annotation

GitHub Actions / Basic validation / build (windows-latest)

'crypto' is defined but never used

Check warning on line 4 in src/classes/state.ts

View workflow job for this annotation

GitHub Actions / Basic validation / build (macos-latest)

'crypto' is defined but never used
import fs from 'fs';
import path from 'path';
// import * as artifact from '@actions/artifact';
import * as core from '@actions/core';
import {restoreCache, saveCache} from '@actions/cache';
import {uploadFile} from './http-client/HttpClient';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';

type IssueID = number;
export class State implements IState {
private readonly options: IIssuesProcessorOptions;
private processedIssuesIDs: Set<IssueID>;
/**
* @private don't mutate in the debug mode
*/
private readonly debug: boolean;
constructor() {
constructor(options: IIssuesProcessorOptions) {
this.options = options;
this.processedIssuesIDs = new Set();
this.debug = core.getInput('debug-only') === 'true';
this.debug = options.debugOnly;
}

isIssueProcessed(issue: Issue) {
Expand All @@ -42,7 +44,10 @@ export class State implements IState {

const serialized = Array.from(this.processedIssuesIDs).join('|');

const tmpDir = os.tmpdir();
// const tmpDir = path.join(os.tmpdir(),crypto.randomBytes(8).readBigUInt64LE(0).toString());
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'state-'));
// const tmpDir = path.join(os.tmpdir(), 'state');
// fs.mkdirSync(tmpDir, {recursive: true});
const file = path.join(
tmpDir,
State.STATE_FILE
Expand All @@ -51,12 +56,14 @@ export class State implements IState {
fs.writeFileSync(file, serialized);

core.debug(
`Persisting state includes info about ${this.processedIssuesIDs.size} issue(s)`
`Persisting state includes info about ${this.processedIssuesIDs.size} issue(s) --> ${serialized}`
);
// const artifactClient = artifact.create();
try {
saveCache([tmpDir], State.ARTIFACT_NAME);
// cacheHttpClient.saveCache(State.ARTIFACT_NAME, file)
// saveCache([tmpDir], State.ARTIFACT_NAME);
// await artifactClient.uploadArtifact(State.ARTIFACT_NAME, [file], tmpDir);
uploadFile(file, this.options.repoToken, State.ARTIFACT_NAME, '1.0');
} catch (error) {
core.warning(
`Persisting the state was not successful due to "${
Expand All @@ -69,7 +76,10 @@ export class State implements IState {
async rehydrate() {
this.reset();

const tmpDir = os.tmpdir();
// const tmpDir = os.mkdtemp() os.tmpdir();
// const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'state-'));
const tmpDir = path.join(os.tmpdir(), 'state');
fs.mkdirSync(tmpDir, {recursive: true});
// const artifactClient = artifact.create();
try {
/*
Expand All @@ -78,7 +88,7 @@ export class State implements IState {
tmpDir
);
*/
await restoreCache([tmpDir], State.ARTIFACT_NAME);
// await restoreCache([tmpDir], State.ARTIFACT_NAME);

/*
const downloadedFiles = fs.readdirSync(downloadResponse.downloadPath);
Expand All @@ -88,21 +98,29 @@ export class State implements IState {
);
}
*/
const serialized = fs.readFileSync(
path.join(tmpDir, State.ARTIFACT_NAME),
{encoding: 'utf8'}
);
if (!fs.existsSync(path.join(tmpDir, State.STATE_FILE))) {
throw Error(
'There is no state persisted, probably because of the very first run or previous run failed'
);
}
const serialized = fs.readFileSync(path.join(tmpDir, State.STATE_FILE), {
encoding: 'utf8'
});

if (serialized.length === 0) return;

const issueIDs = serialized
.split('|')
.map(parseInt)
.map(id => parseInt(id))
.filter(i => !isNaN(i));

this.processedIssuesIDs = new Set(issueIDs);
core.debug(
`Rehydrated state includes info about ${issueIDs.length} issue(s)`
`Rehydrated state includes info about ${
issueIDs.length
} issue(s) <-- ${serialized}, ${JSON.stringify(
issueIDs
)}-${JSON.stringify(serialized.split('|'))}`
);
} catch (error) {
core.warning(
Expand Down
2 changes: 1 addition & 1 deletion src/main.ts
Expand Up @@ -9,7 +9,7 @@ async function _run(): Promise<void> {
try {
const args = _getAndValidateArgs();

const state = StateService.getState();
const state = StateService.getState(args);
await state.rehydrate();

const issueProcessor: IssuesProcessor = new IssuesProcessor(args, state);
Expand Down
5 changes: 3 additions & 2 deletions src/services/state.service.ts
@@ -1,8 +1,9 @@
import {IState} from '../interfaces/state';
import {State} from '../classes/state';
import {IIssuesProcessorOptions} from '../interfaces/issues-processor-options';

export class StateService {
static getState(): IState {
return new State();
static getState(options: IIssuesProcessorOptions): IState {
return new State(options);
}
}

0 comments on commit 6148637

Please sign in to comment.