Compare commits
2 Commits
main
...
feature/di
Author | SHA1 | Date |
---|---|---|
Marius | 261e6c8027 | |
Christian Kaps | a0bcc71348 |
|
@ -1,156 +0,0 @@
|
||||||
# Taken from https://github.com/hrvey/combine-prs-workflow
|
|
||||||
# This action can be triggered manually to combine multiple PRs for
|
|
||||||
# dependency upgrades into a single PR. See the above links for
|
|
||||||
# more details.
|
|
||||||
name: 'Combine PRs'
|
|
||||||
|
|
||||||
# Controls when the action will run - in this case triggered manually
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
branchPrefix:
|
|
||||||
description: 'Branch prefix to find combinable PRs based on'
|
|
||||||
required: true
|
|
||||||
default: 'dependabot'
|
|
||||||
mustBeGreen:
|
|
||||||
description: 'Only combine PRs that are green (status is success). Set to false if repo does not run checks'
|
|
||||||
type: boolean
|
|
||||||
required: true
|
|
||||||
default: true
|
|
||||||
combineBranchName:
|
|
||||||
description: 'Name of the branch to combine PRs into'
|
|
||||||
required: true
|
|
||||||
default: 'combine-prs-branch'
|
|
||||||
ignoreLabel:
|
|
||||||
description: 'Exclude PRs with this label'
|
|
||||||
required: true
|
|
||||||
default: 'nocombine'
|
|
||||||
|
|
||||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
|
||||||
jobs:
|
|
||||||
# This workflow contains a single job called "combine-prs"
|
|
||||||
combine-prs:
|
|
||||||
# The type of runner that the job will run on
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
|
||||||
steps:
|
|
||||||
- uses: actions/github-script@v6
|
|
||||||
id: create-combined-pr
|
|
||||||
name: Create Combined PR
|
|
||||||
with:
|
|
||||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
|
||||||
script: |
|
|
||||||
const pulls = await github.paginate('GET /repos/:owner/:repo/pulls', {
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo
|
|
||||||
});
|
|
||||||
let branchesAndPRStrings = [];
|
|
||||||
let baseBranch = null;
|
|
||||||
let baseBranchSHA = null;
|
|
||||||
for (const pull of pulls) {
|
|
||||||
const branch = pull['head']['ref'];
|
|
||||||
console.log('Pull for branch: ' + branch);
|
|
||||||
if (branch.startsWith('${{ github.event.inputs.branchPrefix }}')) {
|
|
||||||
console.log('Branch matched prefix: ' + branch);
|
|
||||||
let statusOK = true;
|
|
||||||
if(${{ github.event.inputs.mustBeGreen }}) {
|
|
||||||
console.log('Checking green status: ' + branch);
|
|
||||||
const stateQuery = `query($owner: String!, $repo: String!, $pull_number: Int!) {
|
|
||||||
repository(owner: $owner, name: $repo) {
|
|
||||||
pullRequest(number:$pull_number) {
|
|
||||||
commits(last: 1) {
|
|
||||||
nodes {
|
|
||||||
commit {
|
|
||||||
statusCheckRollup {
|
|
||||||
state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`
|
|
||||||
const vars = {
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
pull_number: pull['number']
|
|
||||||
};
|
|
||||||
const result = await github.graphql(stateQuery, vars);
|
|
||||||
const [{ commit }] = result.repository.pullRequest.commits.nodes;
|
|
||||||
const state = commit.statusCheckRollup.state
|
|
||||||
console.log('Validating status: ' + state);
|
|
||||||
if(state != 'SUCCESS') {
|
|
||||||
console.log('Discarding ' + branch + ' with status ' + state);
|
|
||||||
statusOK = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log('Checking labels: ' + branch);
|
|
||||||
const labels = pull['labels'];
|
|
||||||
for(const label of labels) {
|
|
||||||
const labelName = label['name'];
|
|
||||||
console.log('Checking label: ' + labelName);
|
|
||||||
if(labelName == '${{ github.event.inputs.ignoreLabel }}') {
|
|
||||||
console.log('Discarding ' + branch + ' with label ' + labelName);
|
|
||||||
statusOK = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (statusOK) {
|
|
||||||
console.log('Adding branch to array: ' + branch);
|
|
||||||
const prString = '#' + pull['number'] + ' ' + pull['title'];
|
|
||||||
branchesAndPRStrings.push({ branch, prString });
|
|
||||||
baseBranch = pull['base']['ref'];
|
|
||||||
baseBranchSHA = pull['base']['sha'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (branchesAndPRStrings.length == 0) {
|
|
||||||
core.setFailed('No PRs/branches matched criteria');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await github.rest.git.createRef({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
ref: 'refs/heads/' + '${{ github.event.inputs.combineBranchName }}',
|
|
||||||
sha: baseBranchSHA
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
core.setFailed('Failed to create combined branch - maybe a branch by that name already exists?');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let combinedPRs = [];
|
|
||||||
let mergeFailedPRs = [];
|
|
||||||
for(const { branch, prString } of branchesAndPRStrings) {
|
|
||||||
try {
|
|
||||||
await github.rest.repos.merge({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
base: '${{ github.event.inputs.combineBranchName }}',
|
|
||||||
head: branch,
|
|
||||||
});
|
|
||||||
console.log('Merged branch ' + branch);
|
|
||||||
combinedPRs.push(prString);
|
|
||||||
} catch (error) {
|
|
||||||
console.log('Failed to merge branch ' + branch);
|
|
||||||
mergeFailedPRs.push(prString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Creating combined PR');
|
|
||||||
const combinedPRsString = combinedPRs.join('\n');
|
|
||||||
let body = '✅ This PR was created by the Combine PRs action by combining the following PRs:\n' + combinedPRsString;
|
|
||||||
if(mergeFailedPRs.length > 0) {
|
|
||||||
const mergeFailedPRsString = mergeFailedPRs.join('\n');
|
|
||||||
body += '\n\n⚠️ The following PRs were left out due to merge conflicts:\n' + mergeFailedPRsString
|
|
||||||
}
|
|
||||||
await github.rest.pulls.create({
|
|
||||||
owner: context.repo.owner,
|
|
||||||
repo: context.repo.repo,
|
|
||||||
title: 'Combined PR',
|
|
||||||
head: '${{ github.event.inputs.combineBranchName }}',
|
|
||||||
base: baseBranch,
|
|
||||||
body: body
|
|
||||||
});
|
|
|
@ -9,7 +9,7 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [stable, oldstable]
|
go-version: [1.18.x, 1.19.x]
|
||||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
runs-on: ${{ matrix.platform }}
|
runs-on: ${{ matrix.platform }}
|
||||||
env:
|
env:
|
||||||
|
@ -21,7 +21,7 @@ jobs:
|
||||||
|
|
||||||
-
|
-
|
||||||
name: Install Go
|
name: Install Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
-
|
-
|
||||||
name: Docker meta
|
name: Docker meta
|
||||||
id: docker_meta
|
id: docker_meta
|
||||||
uses: docker/metadata-action@v4.4.0
|
uses: docker/metadata-action@v4.3.0
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
ghcr.io/tus/tusd
|
ghcr.io/tus/tusd
|
||||||
|
@ -35,7 +35,7 @@ jobs:
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v2.5.0
|
uses: docker/setup-buildx-action@v2.4.1
|
||||||
with:
|
with:
|
||||||
install: true
|
install: true
|
||||||
|
|
||||||
|
@ -81,10 +81,10 @@ jobs:
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
-
|
-
|
||||||
name: Install Go
|
name: Install Go 1.19
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: 'stable'
|
go-version: '1.19.5'
|
||||||
|
|
||||||
-
|
-
|
||||||
name: Build TUSD
|
name: Build TUSD
|
||||||
|
@ -105,7 +105,7 @@ jobs:
|
||||||
|
|
||||||
-
|
-
|
||||||
name: Deploy to heroku
|
name: Deploy to heroku
|
||||||
uses: akhileshns/heroku-deploy@v3.12.14
|
uses: akhileshns/heroku-deploy@v3.12.13
|
||||||
with:
|
with:
|
||||||
heroku_api_key: ${{secrets.HEROKU_API_KEY}}
|
heroku_api_key: ${{secrets.HEROKU_API_KEY}}
|
||||||
heroku_app_name: ${{secrets.HEROKU_APP_NAME}}
|
heroku_app_name: ${{secrets.HEROKU_APP_NAME}}
|
||||||
|
|
10
Dockerfile
10
Dockerfile
|
@ -1,4 +1,4 @@
|
||||||
FROM --platform=$BUILDPLATFORM golang:1.20.4-alpine AS builder
|
FROM golang:1.20.1-alpine AS builder
|
||||||
WORKDIR /go/src/github.com/tus/tusd
|
WORKDIR /go/src/github.com/tus/tusd
|
||||||
|
|
||||||
# Add gcc and libc-dev early so it is cached
|
# Add gcc and libc-dev early so it is cached
|
||||||
|
@ -19,17 +19,13 @@ COPY pkg/ ./pkg/
|
||||||
ARG GIT_VERSION
|
ARG GIT_VERSION
|
||||||
ARG GIT_COMMIT
|
ARG GIT_COMMIT
|
||||||
|
|
||||||
# Get the operating system and architecture to build for
|
|
||||||
ARG TARGETOS
|
|
||||||
ARG TARGETARCH
|
|
||||||
|
|
||||||
RUN set -xe \
|
RUN set -xe \
|
||||||
&& GOOS=$TARGETOS GOARCH=$TARGETARCH go build \
|
&& GOOS=linux GOARCH=amd64 go build \
|
||||||
-ldflags="-X github.com/tus/tusd/cmd/tusd/cli.VersionName=${GIT_VERSION} -X github.com/tus/tusd/cmd/tusd/cli.GitCommit=${GIT_COMMIT} -X 'github.com/tus/tusd/cmd/tusd/cli.BuildDate=$(date --utc)'" \
|
-ldflags="-X github.com/tus/tusd/cmd/tusd/cli.VersionName=${GIT_VERSION} -X github.com/tus/tusd/cmd/tusd/cli.GitCommit=${GIT_COMMIT} -X 'github.com/tus/tusd/cmd/tusd/cli.BuildDate=$(date --utc)'" \
|
||||||
-o /go/bin/tusd ./cmd/tusd/main.go
|
-o /go/bin/tusd ./cmd/tusd/main.go
|
||||||
|
|
||||||
# start a new stage that copies in the binary built in the previous stage
|
# start a new stage that copies in the binary built in the previous stage
|
||||||
FROM alpine:3.18.0
|
FROM alpine:3.17.2
|
||||||
WORKDIR /srv/tusd-data
|
WORKDIR /srv/tusd-data
|
||||||
|
|
||||||
COPY ./docker/entrypoint.sh /usr/local/share/docker-entrypoint.sh
|
COPY ./docker/entrypoint.sh /usr/local/share/docker-entrypoint.sh
|
||||||
|
|
17
go.mod
17
go.mod
|
@ -6,19 +6,20 @@ module github.com/tus/tusd
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/storage v1.30.1
|
cloud.google.com/go/storage v1.29.0
|
||||||
github.com/Azure/azure-storage-blob-go v0.14.0
|
github.com/Azure/azure-storage-blob-go v0.14.0
|
||||||
github.com/aws/aws-sdk-go v1.44.275
|
github.com/aws/aws-sdk-go v1.44.211
|
||||||
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40
|
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40
|
||||||
github.com/golang/mock v1.6.0
|
github.com/golang/mock v1.6.0
|
||||||
github.com/golang/protobuf v1.5.3
|
github.com/golang/protobuf v1.5.2
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||||
github.com/prometheus/client_golang v1.15.1
|
github.com/prometheus/client_golang v1.14.0
|
||||||
github.com/sethgrid/pester v1.2.0
|
github.com/sethgrid/pester v1.2.0
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.2
|
||||||
github.com/vimeo/go-util v1.4.1
|
github.com/vimeo/go-util v1.4.1
|
||||||
google.golang.org/api v0.125.0
|
golang.org/x/sys v0.6.0 // indirect
|
||||||
google.golang.org/grpc v1.55.0
|
google.golang.org/api v0.111.0
|
||||||
|
google.golang.org/grpc v1.53.0
|
||||||
gopkg.in/Acconut/lockfile.v1 v1.1.0
|
gopkg.in/Acconut/lockfile.v1 v1.1.0
|
||||||
gopkg.in/h2non/gock.v1 v1.1.2
|
gopkg.in/h2non/gock.v1 v1.1.2
|
||||||
)
|
)
|
||||||
|
|
|
@ -53,24 +53,6 @@ func NewHTTPError(err error, statusCode int) HTTPError {
|
||||||
return httpError{err, statusCode}
|
return httpError{err, statusCode}
|
||||||
}
|
}
|
||||||
|
|
||||||
type contextWithValues struct {
|
|
||||||
context.Context
|
|
||||||
valueHolder context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c contextWithValues) Value(key interface{}) interface{} {
|
|
||||||
return c.valueHolder.Value(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newContextWithValues(ctx context.Context) contextWithValues {
|
|
||||||
return contextWithValues{
|
|
||||||
// Use background to not get cancel event
|
|
||||||
Context: context.Background(),
|
|
||||||
// Use request context to get stored values
|
|
||||||
valueHolder: ctx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrUnsupportedVersion = NewHTTPError(errors.New("unsupported version"), http.StatusPreconditionFailed)
|
ErrUnsupportedVersion = NewHTTPError(errors.New("unsupported version"), http.StatusPreconditionFailed)
|
||||||
ErrMaxSizeExceeded = NewHTTPError(errors.New("maximum size exceeded"), http.StatusRequestEntityTooLarge)
|
ErrMaxSizeExceeded = NewHTTPError(errors.New("maximum size exceeded"), http.StatusRequestEntityTooLarge)
|
||||||
|
@ -116,12 +98,6 @@ type HookEvent struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHookEvent(info FileInfo, r *http.Request) HookEvent {
|
func newHookEvent(info FileInfo, r *http.Request) HookEvent {
|
||||||
// The Host header field is not present in the header map, see https://pkg.go.dev/net/http#Request:
|
|
||||||
// > For incoming requests, the Host header is promoted to the
|
|
||||||
// > Request.Host field and removed from the Header map.
|
|
||||||
// That's why we add it back manually.
|
|
||||||
r.Header.Set("Host", r.Host)
|
|
||||||
|
|
||||||
return HookEvent{
|
return HookEvent{
|
||||||
Upload: info,
|
Upload: info,
|
||||||
HTTPRequest: HTTPRequest{
|
HTTPRequest: HTTPRequest{
|
||||||
|
@ -308,7 +284,7 @@ func (handler *UnroutedHandler) Middleware(h http.Handler) http.Handler {
|
||||||
// PostFile creates a new file upload using the datastore after validating the
|
// PostFile creates a new file upload using the datastore after validating the
|
||||||
// length and parsing the metadata.
|
// length and parsing the metadata.
|
||||||
func (handler *UnroutedHandler) PostFile(w http.ResponseWriter, r *http.Request) {
|
func (handler *UnroutedHandler) PostFile(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContextWithValues(r.Context())
|
ctx := context.Background()
|
||||||
|
|
||||||
// Check for presence of application/offset+octet-stream. If another content
|
// Check for presence of application/offset+octet-stream. If another content
|
||||||
// type is defined, it will be ignored and treated as none was set because
|
// type is defined, it will be ignored and treated as none was set because
|
||||||
|
@ -451,7 +427,7 @@ func (handler *UnroutedHandler) PostFile(w http.ResponseWriter, r *http.Request)
|
||||||
|
|
||||||
// HeadFile returns the length and offset for the HEAD request
|
// HeadFile returns the length and offset for the HEAD request
|
||||||
func (handler *UnroutedHandler) HeadFile(w http.ResponseWriter, r *http.Request) {
|
func (handler *UnroutedHandler) HeadFile(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContextWithValues(r.Context())
|
ctx := context.Background()
|
||||||
|
|
||||||
id, err := extractIDFromPath(r.URL.Path)
|
id, err := extractIDFromPath(r.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -516,7 +492,7 @@ func (handler *UnroutedHandler) HeadFile(w http.ResponseWriter, r *http.Request)
|
||||||
// PatchFile adds a chunk to an upload. This operation is only allowed
|
// PatchFile adds a chunk to an upload. This operation is only allowed
|
||||||
// if enough space in the upload is left.
|
// if enough space in the upload is left.
|
||||||
func (handler *UnroutedHandler) PatchFile(w http.ResponseWriter, r *http.Request) {
|
func (handler *UnroutedHandler) PatchFile(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContextWithValues(r.Context())
|
ctx := context.Background()
|
||||||
|
|
||||||
// Check for presence of application/offset+octet-stream
|
// Check for presence of application/offset+octet-stream
|
||||||
if r.Header.Get("Content-Type") != "application/offset+octet-stream" {
|
if r.Header.Get("Content-Type") != "application/offset+octet-stream" {
|
||||||
|
@ -745,7 +721,7 @@ func (handler *UnroutedHandler) finishUploadIfComplete(ctx context.Context, uplo
|
||||||
// GetFile handles requests to download a file using a GET request. This is not
|
// GetFile handles requests to download a file using a GET request. This is not
|
||||||
// part of the specification.
|
// part of the specification.
|
||||||
func (handler *UnroutedHandler) GetFile(w http.ResponseWriter, r *http.Request) {
|
func (handler *UnroutedHandler) GetFile(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContextWithValues(r.Context())
|
ctx := context.Background()
|
||||||
|
|
||||||
id, err := extractIDFromPath(r.URL.Path)
|
id, err := extractIDFromPath(r.URL.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -866,7 +842,7 @@ func filterContentType(info FileInfo) (contentType string, contentDisposition st
|
||||||
|
|
||||||
// DelFile terminates an upload permanently.
|
// DelFile terminates an upload permanently.
|
||||||
func (handler *UnroutedHandler) DelFile(w http.ResponseWriter, r *http.Request) {
|
func (handler *UnroutedHandler) DelFile(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := newContextWithValues(r.Context())
|
ctx := context.Background()
|
||||||
|
|
||||||
// Abort the request handling if the required interface is not implemented
|
// Abort the request handling if the required interface is not implemented
|
||||||
if !handler.composer.UsesTerminater {
|
if !handler.composer.UsesTerminater {
|
||||||
|
|
Loading…
Reference in New Issue