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
49 changes: 48 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ on:
push:
branches:
- main
workflow_run:
workflows:
- Release
types:
- completed
branches:
- main

permissions:
contents: read
Expand All @@ -15,6 +22,7 @@ jobs:
test-typescript:
name: TypeScript Tests
runs-on: ubuntu-latest
if: github.event_name != 'workflow_run'

steps:
- name: Checkout
Expand Down Expand Up @@ -47,15 +55,54 @@ jobs:
cfx-portal-upload:
name: GitHub Actions Test
runs-on: ubuntu-latest
if: github.event_name == 'push'
if:
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success'

steps:
- name: Checkout
id: checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
fetch-depth: 0
fetch-tags: true

- name: Get Release Version
id: release-version
shell: bash
run: |
git fetch --force --tags

tag="$(git tag --points-at "${{ github.event.workflow_run.head_sha }}" | sort -V | tail -n 1)"
if [ -z "$tag" ]; then
echo "No release tag found for ${{ github.event.workflow_run.head_sha }}. Skipping portal upload."
echo "should_upload=false" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "tag=${tag}" >> "$GITHUB_OUTPUT"
echo "version=${tag#v}" >> "$GITHUB_OUTPUT"
echo "should_upload=true" >> "$GITHUB_OUTPUT"

- name: Update Test Asset Version
id: update-test-version
if: steps.release-version.outputs.should_upload == 'true'
shell: bash
run: |
version="${{ steps.release-version.outputs.version }}"
workdir="$(mktemp -d)"
trap 'rm -rf "$workdir"' EXIT

unzip -q ./test.zip -d "$workdir"
sed -i -E "s/^version ['\"][^'\"]+['\"]/version \"${version}\"/" "$workdir/test/fxmanifest.lua"

rm ./test.zip
(cd "$workdir" && zip -qr "$GITHUB_WORKSPACE/test.zip" test)

- name: Test Local Action
id: cfx-portal-upload
if: steps.release-version.outputs.should_upload == 'true'
uses: ./
with:
cookie: ${{ secrets.FORUM_COOKIE }}
Expand Down
127 changes: 126 additions & 1 deletion __tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ describe('main', () => {
}
})
;(utils.getAssetVersions as jest.Mock).mockResolvedValue([
{ id: 456, version: '1.0.0' },
{ id: 456, version: '1.0.0', state: 'active' },
{ id: 111, version: '0.9.0' }
])

Expand All @@ -364,6 +364,131 @@ describe('main', () => {
)
})

it('should wait for the uploaded version to become active before deleting older versions', async () => {
jest.useFakeTimers()

try {
;(core.getInput as jest.Mock).mockImplementation((name: string) => {
switch (name) {
case 'assetId':
return '123'
case 'zipPath':
return 'test.zip'
case 'cookie':
return 'test-cookie'
case 'chunkSize':
return '1024'
case 'maxRetries':
return '1'
case 'deleteOlderVersions':
return 'true'
case 'makeZip':
case 'skipUpload':
case 'beta':
return 'false'
default:
return ''
}
})

pageMock.evaluate.mockResolvedValueOnce({ url: 'https://forum-redirect' })
pageMock.url.mockReturnValue('https://portal.cfx.re')
;(utils.getFxManifestVersion as jest.Mock).mockReturnValue('1.0.0')
;(utils.getChangelog as jest.Mock).mockReturnValue('test changelog')
;(axios.post as jest.Mock).mockResolvedValue({
data: {
asset_id: 123,
version_id: 456,
errors: null
}
})
;(utils.getAssetVersions as jest.Mock)
.mockResolvedValueOnce([
{ id: 456, version: '1.0.0', state: 'processing' },
{ id: 111, version: '0.9.0', state: 'active' }
])
.mockResolvedValueOnce([
{ id: 456, version: '1.0.0', state: 'active' },
{ id: 111, version: '0.9.0', state: 'active' }
])

const runPromise = main.run()
await jest.runAllTimersAsync()
await runPromise

expect(utils.getAssetVersions).toHaveBeenCalledTimes(2)
expect(utils.deleteAssetVersion).toHaveBeenCalledWith(
'123',
111,
expect.anything()
)
expect(utils.deleteAssetVersion).not.toHaveBeenCalledWith(
'123',
456,
expect.anything()
)
} finally {
jest.useRealTimers()
}
})

it('should fail after timing out while waiting for the uploaded version to become active', async () => {
;(core.getInput as jest.Mock).mockImplementation((name: string) => {
switch (name) {
case 'assetId':
return '123'
case 'zipPath':
return 'test.zip'
case 'cookie':
return 'test-cookie'
case 'chunkSize':
return '1024'
case 'maxRetries':
return '1'
case 'deleteOlderVersions':
return 'true'
case 'makeZip':
case 'skipUpload':
case 'beta':
return 'false'
default:
return ''
}
})

pageMock.evaluate.mockResolvedValueOnce({ url: 'https://forum-redirect' })
pageMock.url.mockReturnValue('https://portal.cfx.re')
;(utils.getFxManifestVersion as jest.Mock).mockReturnValue('1.0.0')
;(utils.getChangelog as jest.Mock).mockReturnValue('test changelog')
;(axios.post as jest.Mock).mockResolvedValue({
data: {
asset_id: 123,
version_id: 456,
errors: null
}
})
;(utils.getAssetVersions as jest.Mock).mockResolvedValue([
{ id: 456, version: '1.0.0', state: 'processing' },
{ id: 111, version: '0.9.0', state: 'active' }
])

const dateNow = jest
.spyOn(Date, 'now')
.mockReturnValueOnce(0)
.mockReturnValueOnce(60000)

try {
await main.run()

expect(core.setFailed).toHaveBeenCalledWith(
'Timed out waiting for version 456 to become active (last state: processing)'
)
expect(utils.deleteAssetVersion).not.toHaveBeenCalled()
} finally {
dateNow.mockRestore()
}
})

it('should skip upload if skipUpload is true', async () => {
;(core.getInput as jest.Mock).mockImplementation((name: string) => {
if (name === 'skipUpload') return 'true'
Expand Down
2 changes: 1 addition & 1 deletion badges/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 18 additions & 1 deletion dist/index.mjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions dist/index.mjs.map

Large diffs are not rendered by default.

26 changes: 25 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,34 @@ export async function run(): Promise<void> {
changelog
)

core.debug(`Uploaded version ID: ${uploadedVersionId}`)

if (deleteOlderVersions) {
core.info('Deleting older versions ...')
const versions = await getAssetVersions(assetId, cookies)
let versions = await getAssetVersions(assetId, cookies)
let assetVersionInfo = versions.find(v => v.id === uploadedVersionId)

const start = Date.now()

while (assetVersionInfo?.state !== 'active') {
if (Date.now() - start >= 60000) {
throw new Error(
`Timed out waiting for version ${uploadedVersionId} to become active ` +
`(last state: ${assetVersionInfo?.state ?? 'unknown'})`
)
}

await new Promise(resolve => setTimeout(resolve, 1000))
versions = await getAssetVersions(assetId, cookies)
assetVersionInfo = versions.find(v => v.id === uploadedVersionId)
}

core.debug(`Versions: ${JSON.stringify(versions)}`)

for (const v of versions) {
core.debug(
`Checking version ${v.id} against ${uploadedVersionId}, ${v.id !== uploadedVersionId}`
)
if (v.id !== uploadedVersionId) {
await deleteAssetVersion(assetId, v.id, cookies)
}
Expand Down
Loading