Skip to content

Step 3 - Release VSIX packages #268

Step 3 - Release VSIX packages

Step 3 - Release VSIX packages #268

Workflow file for this run

name: Step 3 - Release VSIX packages
on:
workflow_run:
workflows: ["Step 2 - Build VSIX packages"]
types:
- completed
workflow_dispatch:
inputs:
force_release:
description: 'Override any failure conditions in uploading release artifacts, to release to Open VSX'
type: boolean
default: false
required: false
jobs:
release:
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
- name: Find Latest Successful CI Run
id: find-ci-run
uses: actions/github-script@v6
with:
script: |
const runs = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: "ci-build.yml",
status: "success",
per_page: 1
});
if (runs.data.workflow_runs.length === 0) {
throw new Error("No successful workflow runs found");
}
return runs.data.workflow_runs[0].id;
- name: Set Workflow Run ID
run: echo "WORKFLOW_RUN_ID=${{ steps.find-ci-run.outputs.result }}" >> $GITHUB_ENV
- name: Download all build artifacts
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const path = require('path');
const runId = process.env.WORKFLOW_RUN_ID;
const outputPath = './vsix-release';
async function downloadArtifact(url, dest) {
const response = await fetch(url, {
//headers: {
// Authorization: `Bearer ${process.env.GH_TOKEN}`,
//}
});
if (!response.ok) throw new Error(`Failed to fetch ${url} - ${response.statusText}`);
const fileStream = fs.createWriteStream(dest);
return new Promise((resolve, reject) => {
response.body.pipe(fileStream);
response.body.on('error', reject);
fileStream.on('finish', resolve);
});
}
async function main() {
const { data: artifacts } = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: runId,
});
if (!fs.existsSync(outputPath)) {
fs.mkdirSync(outputPath, { recursive: true });
}
for (const artifact of artifacts.artifacts) {
core.notice(`Getting redirect URL for artifact ${artifact.id} ${artifact.name}`)
const result = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: artifact.id,
archive_format: 'zip',
});
const dest = path.join(outputPath, `${artifact.name}.zip`);
core.notice(`Downloading ${result.url} to ${dest}`)
await downloadArtifact(result.url, dest);
}
}
main().catch(error => {
core.setFailed(error.message);
});
env:
WORKFLOW_RUN_ID: ${{ env.WORKFLOW_RUN_ID }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Extract build artifacts
run: |
for zipfile in ./vsix-release/*.zip; do
base_name=$(basename "$zipfile" .zip)
extract_dir="vsix-release/${base_name}_tmp/"
7z x "$zipfile" -o"$extract_dir" > /dev/null
extracted_file=$(find "$extract_dir" -type f)
extension="${extracted_file##*.}"
echo "$extracted_file"
mv "$extracted_file" "vsix-release/${base_name}"
rm -rf "$extract_dir"
done
- name: Display structure of downloaded files
run: |
ls -R ./vsix-release
- name: Get package version
run: node -e "console.log('VERSION=' + require('./package.json').version)" >> $GITHUB_ENV
- name: Set Force Release Override from Manual Worfklow Dispatch
if: github.event_name == 'workflow_dispatch'
run: echo "FORCE_RELEASE=${{ github.event.inputs.force_release }}" >> $GITHUB_ENV
- name: Set Force Release Override from Commit Message
if: github.event_name == 'push'
run: |
if [[ "$(git log -1 --pretty=%B)" == *"[force-release]"* ]]; then
echo "FORCE_RELEASE=true" >> $GITHUB_ENV
else
echo "FORCE_RELEASE=false" >> $GITHUB_ENV
fi
- name: Create GitHub Release
id: create_release
uses: actions/github-script@v6
continue-on-error: true
with:
script: |
try {
const response = await github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: `v${process.env.VERSION}`,
name: `Release ${process.env.VERSION}`,
draft: false,
prerelease: false,
});
core.setOutput('upload_url', response.data.upload_url);
} catch (error) {
if (error.status === 422 && error.message.includes('already_exists')) {
console.log('Release already exists. Retrieving existing release upload URL.');
const releases = await github.rest.repos.listReleases({
owner: context.repo.owner,
repo: context.repo.repo,
});
const existingRelease = releases.data.find(release => release.tag_name === `v${process.env.VERSION}`);
if (existingRelease) {
core.setOutput('upload_url', existingRelease.upload_url);
} else {
throw new Error('Release exists but could not find it.');
}
} else {
throw error;
}
}
- name: Upload release builds
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const path = require('path');
const forceReleaseVar = process.env.FORCE_RELEASE
const forceRelease = forceReleaseVar === "true" || forceReleaseVar === true
if (forceRelease) {
console.log("FORCE_RELEASE is true - errors will be logged but ignored")
}
const releasesPath = path.join(process.env.GITHUB_WORKSPACE, 'vsix-release')
const releasePlatforms = [
'darwin-x64', 'linux-x64', 'win32-x64',
'platform-neutral'
]
const artifacts = releasePlatforms.map(
platform => ({
path: path.join(releasesPath, `csharp-${platform}.vsix`),
name: `csharp-${platform}-${process.env.VERSION}.vsix`
})
)
const uploadedArtifacts = []
for (const artifact of artifacts) {
if (fs.existsSync(artifact.path)) {
console.log(`Uploading ${artifact.name}...`);
await github.rest.repos.uploadReleaseAsset({
url: '${{ steps.create_release.outputs.upload_url }}',
headers: {
'content-type': 'application/zip',
'content-length': fs.statSync(artifact.path).size
},
name: artifact.name,
data: fs.readFileSync(artifact.path)
}).then(response => {
console.log(`Uploaded ${artifact.name}`);
uploadedArtifacts.push(artifact)
}).catch(error => {
const msg = `Failed to upload ${artifact.name}: ${error}`
if (forceRelease) {
console.log(msg)
} else {
console.error(msg);
}
});
} else {
console.log(`File ${artifact.path} does not exist. Skipping upload.`);
}
}
if (!uploadedArtifacts.length) {
const msg = "Did not find any artifacts to upload"
if (forceRelease) {
console.log(msg)
} else {
throw new Error(msg)
}
}
- name: Install Node.js 18.x
uses: actions/setup-node@v4
with:
node-version: '18.x'
- name: Publish to Open-VSX
run: |
npm ci
npm i -g ovsx
ovsx publish --packagePath $(find ./vsix-release -iname *.vsix) -p ${{ secrets.OPEN_VSX_TOKEN }}