diff --git a/.woodpecker.release/package.json b/.woodpecker.release/package.json new file mode 100644 index 0000000..269e73f --- /dev/null +++ b/.woodpecker.release/package.json @@ -0,0 +1,17 @@ +{ + "name": "codeberg-release-tool", + "version": "0.1.0", + "license": "Apache-2.0", + "scripts": { + "build": "tsc", + "start": "node dist/release.js" + }, + "dependencies": { + "axios": "^0.21.1", + "form-data": "^4.0.0" + }, + "devDependencies": { + "@types/node": "^20.5.0", + "typescript": "^4.2.4" + } +} diff --git a/.woodpecker.release/release.ts b/.woodpecker.release/release.ts new file mode 100644 index 0000000..2d6e2f3 --- /dev/null +++ b/.woodpecker.release/release.ts @@ -0,0 +1,113 @@ +import axios from 'axios'; +import fs from 'fs'; +import path from 'path'; +import FormData from 'form-data'; + + +// Environment Variables: +// CB_API_KEY: The API key for accessing Codeberg. + +// TODO: change this to match +const repoUrl = 'https://codeberg.org/api/v1/repos/threadpanic/cb-src-woodpecker'; + + + + +// Extract the command-line argument and assign to 'version' +const version = process.argv[2]; +if (!version) { + console.error('Please provide the version as a command-line argument.'); + process.exit(1); +} + +const tarball_artifact = `librewolf-${version}.source.tar.gz`; +const sha256sum_artifact = `${tarball_artifact}.sha256sum`; +const tarballExists = fs.existsSync(path.join('..', tarball_artifact)); +const sha256sumExists = fs.existsSync(path.join('..', sha256sum_artifact)); + +if (!tarballExists || !sha256sumExists) { + console.error(`Missing artifacts. Ensure both ${tarball_artifact} and ${sha256sum_artifact} are present in the parent directory.`); + process.exit(1); +} + +const apiKey = process.env.CB_API_KEY; + +if (!apiKey) { + console.error('API key not found in environment variable CB_API_KEY.'); + process.exit(1); +} + +const headers = { + 'Authorization': `Bearer ${apiKey}` +}; + +async function addReleaseArtifact(fileName: string, releaseId: number) { + const apiUrl = `${repoUrl}/releases/${releaseId}/assets?name=${fileName}`; + const formData = new FormData(); + formData.append('attachment', fs.createReadStream(path.join('..', fileName))); + + try { + const response = await axios.post(apiUrl, formData, { + headers: { + ...headers, + ...formData.getHeaders() + } + }); + + if (response.status !== 201) { + throw new Error(`Failed to attach artifact ${fileName}. Unexpected response status: ${response.status}`); + } + } catch (error: any) { + console.error(`Error while attaching artifact ${fileName}:`, error.response ? error.response.data : error.message); + throw error; + } +} + +async function createNewRelease() { + const releaseUrl = `${repoUrl}/releases`; + const requestBody = { + body: `Release v${version} of the LibreWolf source tarball. Please see the README.md file for compilation instructions and dependency details.`, + draft: false, + name: `Release ${version}`, + prerelease: false, + tag_name: `v${version}` + }; + + try { + const response = await axios.post(releaseUrl, requestBody, { headers: headers }); + + if (response.status === 201) { + await addReleaseArtifact(tarball_artifact, response.data.id); + await addReleaseArtifact(sha256sum_artifact, response.data.id); + } else { + throw new Error(`Failed to create release. Unexpected response status: ${response.status}`); + } + } catch (error: any) { + console.error("Error while creating release:", error.response ? error.response.data : error.message); + throw error; + } +} + +async function main() { + try { + const releaseListResponse = await axios.get(`${repoUrl}/releases`); + + if (releaseListResponse.data.length === 0) { + await createNewRelease(); + } else { + const latestReleaseResponse = await axios.get(`${repoUrl}/releases/latest`); + if (latestReleaseResponse.data.tag_name === `v${version}`) { + console.log(`Version v${version} already exists as a release. Exiting without creating a new release.`); + process.exit(0); + } + await createNewRelease(); + } + process.exit(0); + } catch (error: any) { + console.error('Error while processing releases:', error); + process.exit(1); + } +} + +main(); + diff --git a/.woodpecker.release/tsconfig.json b/.woodpecker.release/tsconfig.json new file mode 100644 index 0000000..330f53f --- /dev/null +++ b/.woodpecker.release/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist" + }, + "include": [ + "release.ts" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..0b5d309 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,57 @@ +steps: + + fetch: + image: alpine + commands: + - apk update -U + - apk add make gnupg + + - make fetch-upstream-woodpecker + + test: + image: alpine + commands: + - apk update -U + - apk add make patch + + - make check-patchfail-woodpecker + + build: + image: alpine + commands: + - apk update -U + - apk add make gnupg patch python3 bash xz + + - make all + +# +# release: +# image: alpine +# commands: +# - apk update -U +# - apk add nodejs npm +# +# - ( cd .woodpecker.release && npm install && npm run build ) +# - ( cd .woodpecker.release && npm run start $(cat ../version)-$(cat ../release) ) +# +# secrets: [ cb_api_key ] +# + + + upload: + image: woodpeckerci/plugin-s3 + + settings: + bucket: artifacts + source: "*.{tar.gz,sha256sum}" + target: /${CI_BUILD_NUMBER} + path_style: true + endpoint: https://storage.ci.librewolf.net + + secrets: [aws_access_key_id, aws_secret_access_key] + + display-links: + image: alpine + commands: + - echo "https://storage.ci.librewolf.net/artifacts/${CI_BUILD_NUMBER}/librewolf-$(cat version)-$(cat release).source.tar.gz" + - echo "https://storage.ci.librewolf.net/artifacts/${CI_BUILD_NUMBER}/librewolf-$(cat version)-$(cat release).source.tar.gz.sha256sum" diff --git a/Makefile b/Makefile index 1dfb5e3..ebf9d62 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ docker_targets=docker-build-image docker-run-build-job docker-remove-image - -.PHONY : help check all clean veryclean dir bootstrap fetch build package run update setup-wasi check-patchfail check-fuzz fixfuzz $(docker_targets) +woodpecker_targets=fetch-upstream-woodpecker check-patchfail-woodpecker +.PHONY : help check all clean veryclean dir bootstrap fetch build package run update setup-wasi check-patchfail check-fuzz fixfuzz $(docker_targets) $(woodpecker_targets) version:=$(shell cat ./version) release:=$(shell cat ./release) @@ -93,12 +93,15 @@ $(lw_source_dir) : $(ff_source_tarball) ./version ./release scripts/librewolf-pa $(lw_source_tarball) : $(lw_source_dir) rm -f $(lw_source_tarball) - $(archive_create) $(lw_source_tarball) $(lw_source_dir) + tar cf librewolf-$(version)-$(release).source.tar $(lw_source_dir) + time gzip --fast librewolf-$(version)-$(release).source.tar touch $(lw_source_dir) sha256sum $(lw_source_tarball) > $(lw_source_tarball).sha256sum cat $(lw_source_tarball).sha256sum + sha256sum -c $(lw_source_tarball).sha256sum [ "$(SIGNING_KEY)" != "" ] && cp -v $(SIGNING_KEY) pk.asc ; true if [ -f pk.asc ]; then gpg --import pk.asc; gpg --detach-sign $(lw_source_tarball) && ls -lh $(lw_source_tarball).sig; fi + ls -lh $(lw_source_tarball)* debs=python3 python3-dev python3-pip @@ -124,8 +127,12 @@ package : run : (cd $(lw_source_dir) && ./mach run) + check-patchfail: sh -c "./scripts/check-patchfail.sh" > patchfail.out + + + check-fuzz: -sh -c "./scripts/check-patchfail.sh --fuzz=0" > patchfail-fuzz.out fixfuzz : @@ -158,3 +165,18 @@ setup-debian : setup-fedora : dnf -y install python3 curl wget zstd python3-devel python3-pip mercurial openssl-devel libxml2-devel + + + + + +# +# for .woodpecker.yml +# + +check-patchfail-woodpecker : + + ( sh -c "./scripts/check-patchfail.sh" > patchfail.out ; exit_code=$$? ; \ + cat patchfail.out ; rm -f patchfail.out ; exit $$exit_code ) + +fetch-upstream-woodpecker : fetch diff --git a/version b/version index 3722fe1..d8f681e 100644 --- a/version +++ b/version @@ -1 +1 @@ -116.0.2 +116.0.3