Skip to content

Commit

Permalink
Merge branch 'master' into fix-allday-events
Browse files Browse the repository at this point in the history
* master: (53 commits)
  New tool
  Merged
  Add method to remove property
  Move targeted Go version to 1.20
  Remove deprecated ioutil
  Improve error for property not found
  Should be able to distinguish unset from invalid time properties
  Add ComponentPropertyRelatedTo; the VTODO component can have that
  fix: reduce build restriction on serialization test
  fix: add test err assertion
  refactor: switch syntax
  refactor: reduce scope of gitignore
  refactor: fix linting errors
  breaking: unescape Property.Value of type TEXT
  fix: VFREEBUSY serialization
  add: serialiation test
  add: stable serialization of property parameters
  fix: use macos-13, arm is not supported by setup-go
  fix: explicitly list golang versions
  fix: simplify & update ghas
  ...

# Conflicts:
#	components.go
#	property.go
  • Loading branch information
arran4 committed Sep 28, 2024
2 parents 320d5fd + c9951e3 commit 0c815e1
Show file tree
Hide file tree
Showing 33 changed files with 1,262 additions and 246 deletions.
20 changes: 7 additions & 13 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,15 @@ on:
pull_request:
jobs:
golangci:
name: lint
name: Lint
runs-on: ubuntu-latest
permissions:
contents: read # allow read access to the content for analysis.
checks: write # allow write access to checks to allow the action to annotate code in the PR.
steps:
- uses: actions/checkout@v2
- name: Cache-Go
uses: actions/cache@v1
with:
path: |
~/go/pkg/mod # Module download cache
~/.cache/go-build # Build cache (Linux)
~/Library/Caches/go-build # Build cache (Mac)
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
- name: Checkout
uses: actions/checkout@v4
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
uses: golangci/golangci-lint-action@v6
with:
version: latest
11 changes: 11 additions & 0 deletions .github/workflows/goleaks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: gitleaks
on: [push,pull_request]
jobs:
gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: gitleaks-action
uses: zricethezav/gitleaks-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
11 changes: 11 additions & 0 deletions .github/workflows/govun.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: Go vunderability check
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
- id: govulncheck
uses: golang/govulncheck-action@v1
49 changes: 30 additions & 19 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@
on: [push, pull_request]
name: Test
jobs:
test:
version:
name: Test
permissions:
contents: read
strategy:
matrix:
go-version: [1.14.x, 1.15.x, 1.16.x, 1.17.x]
os: [ubuntu-latest, macos-latest, windows-latest]
go-version: ['oldstable', 'stable']
os: [ubuntu-latest, macos-13, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Install Go
uses: actions/setup-go@v2
- name: Checkout
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Cache-Go
uses: actions/cache@v1
go-version: "${{ matrix.go-version }}"
- name: Go Test
run: go test -race ./...
module:
name: Test
permissions:
contents: read
strategy:
matrix:
go-version-file: ['go.mod']
os: [ubuntu-latest, macos-13, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Golang
uses: actions/setup-go@v5
with:
path: |
~/go/pkg/mod # Module download cache
~/.cache/go-build # Build cache (Linux)
~/Library/Caches/go-build # Build cache (Mac)
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
- name: Checkout code
uses: actions/checkout@v2
- name: Test
run: go test ./...
go-version-file: "${{ matrix.go-version-file }}"
- name: Go Test
run: go test -race ./...
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/.idea/
/testdata/serialization/actual
17 changes: 17 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Contributing

## Linting
Make sure your code has been linted using [golangci-lint](https://github.com/golangci/golangci-lint?tab=readme-ov-file#install-golangci-lint)

```shell
$ golangci-lint run
```

## Tests

If you want to submit a bug fix or new feature, make sure that all tests are passing.
```shell
$ go test ./...
```


138 changes: 57 additions & 81 deletions calendar.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,41 @@ const (
type ComponentProperty Property

const (
ComponentPropertyUniqueId = ComponentProperty(PropertyUid) // TEXT
ComponentPropertyDtstamp = ComponentProperty(PropertyDtstamp)
ComponentPropertyOrganizer = ComponentProperty(PropertyOrganizer)
ComponentPropertyAttendee = ComponentProperty(PropertyAttendee)
ComponentPropertyAttach = ComponentProperty(PropertyAttach)
ComponentPropertyDescription = ComponentProperty(PropertyDescription) // TEXT
ComponentPropertyCategories = ComponentProperty(PropertyCategories) // TEXT
ComponentPropertyClass = ComponentProperty(PropertyClass) // TEXT
ComponentPropertyColor = ComponentProperty(PropertyColor) // TEXT
ComponentPropertyCreated = ComponentProperty(PropertyCreated)
ComponentPropertySummary = ComponentProperty(PropertySummary) // TEXT
ComponentPropertyDtStart = ComponentProperty(PropertyDtstart)
ComponentPropertyDtEnd = ComponentProperty(PropertyDtend)
ComponentPropertyLocation = ComponentProperty(PropertyLocation) // TEXT
ComponentPropertyStatus = ComponentProperty(PropertyStatus) // TEXT
ComponentPropertyFreebusy = ComponentProperty(PropertyFreebusy)
ComponentPropertyLastModified = ComponentProperty(PropertyLastModified)
ComponentPropertyUrl = ComponentProperty(PropertyUrl)
ComponentPropertyGeo = ComponentProperty(PropertyGeo)
ComponentPropertyTransp = ComponentProperty(PropertyTransp)
ComponentPropertySequence = ComponentProperty(PropertySequence)
ComponentPropertyExdate = ComponentProperty(PropertyExdate)
ComponentPropertyExrule = ComponentProperty(PropertyExrule)
ComponentPropertyRdate = ComponentProperty(PropertyRdate)
ComponentPropertyRrule = ComponentProperty(PropertyRrule)
ComponentPropertyAction = ComponentProperty(PropertyAction)
ComponentPropertyTrigger = ComponentProperty(PropertyTrigger)
ComponentPropertyUniqueId = ComponentProperty(PropertyUid) // TEXT
ComponentPropertyDtstamp = ComponentProperty(PropertyDtstamp)
ComponentPropertyOrganizer = ComponentProperty(PropertyOrganizer)
ComponentPropertyAttendee = ComponentProperty(PropertyAttendee)
ComponentPropertyAttach = ComponentProperty(PropertyAttach)
ComponentPropertyDescription = ComponentProperty(PropertyDescription) // TEXT
ComponentPropertyCategories = ComponentProperty(PropertyCategories) // TEXT
ComponentPropertyClass = ComponentProperty(PropertyClass) // TEXT
ComponentPropertyColor = ComponentProperty(PropertyColor) // TEXT
ComponentPropertyCreated = ComponentProperty(PropertyCreated)
ComponentPropertySummary = ComponentProperty(PropertySummary) // TEXT
ComponentPropertyDtStart = ComponentProperty(PropertyDtstart)
ComponentPropertyDtEnd = ComponentProperty(PropertyDtend)
ComponentPropertyLocation = ComponentProperty(PropertyLocation) // TEXT
ComponentPropertyStatus = ComponentProperty(PropertyStatus) // TEXT
ComponentPropertyFreebusy = ComponentProperty(PropertyFreebusy)
ComponentPropertyLastModified = ComponentProperty(PropertyLastModified)
ComponentPropertyUrl = ComponentProperty(PropertyUrl)
ComponentPropertyGeo = ComponentProperty(PropertyGeo)
ComponentPropertyTransp = ComponentProperty(PropertyTransp)
ComponentPropertySequence = ComponentProperty(PropertySequence)
ComponentPropertyExdate = ComponentProperty(PropertyExdate)
ComponentPropertyExrule = ComponentProperty(PropertyExrule)
ComponentPropertyRdate = ComponentProperty(PropertyRdate)
ComponentPropertyRrule = ComponentProperty(PropertyRrule)
ComponentPropertyAction = ComponentProperty(PropertyAction)
ComponentPropertyTrigger = ComponentProperty(PropertyTrigger)
ComponentPropertyPriority = ComponentProperty(PropertyPriority)
ComponentPropertyResources = ComponentProperty(PropertyResources)
ComponentPropertyCompleted = ComponentProperty(PropertyCompleted)
ComponentPropertyDue = ComponentProperty(PropertyDue)
ComponentPropertyPercentComplete = ComponentProperty(PropertyPercentComplete)
ComponentPropertyTzid = ComponentProperty(PropertyTzid)
ComponentPropertyComment = ComponentProperty(PropertyComment)
ComponentPropertyRelatedTo = ComponentProperty(PropertyRelatedTo)
)

type Property string
Expand Down Expand Up @@ -213,7 +221,7 @@ const (
)

func (ps ObjectStatus) KeyValue(s ...interface{}) (string, []string) {
return string(PropertyStatus), []string{ToText(string(ps))}
return string(PropertyStatus), []string{string(ps)}
}

type RelationshipType string
Expand Down Expand Up @@ -298,84 +306,84 @@ func (calendar *Calendar) Serialize() string {
}

func (calendar *Calendar) SerializeTo(w io.Writer) error {
fmt.Fprint(w, "BEGIN:VCALENDAR", "\r\n")
_, _ = fmt.Fprint(w, "BEGIN:VCALENDAR", "\r\n")
for _, p := range calendar.CalendarProperties {
p.serialize(w)
}
for _, c := range calendar.Components {
c.serialize(w)
c.SerializeTo(w)
}
fmt.Fprint(w, "END:VCALENDAR", "\r\n")
_, _ = fmt.Fprint(w, "END:VCALENDAR", "\r\n")
return nil
}

func (calendar *Calendar) SetMethod(method Method, props ...PropertyParameter) {
calendar.setProperty(PropertyMethod, ToText(string(method)), props...)
calendar.setProperty(PropertyMethod, string(method), props...)
}

func (calendar *Calendar) SetXPublishedTTL(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyXPublishedTTL, string(s), props...)
calendar.setProperty(PropertyXPublishedTTL, s, props...)
}

func (calendar *Calendar) SetVersion(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyVersion, ToText(s), props...)
calendar.setProperty(PropertyVersion, s, props...)
}

func (calendar *Calendar) SetProductId(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyProductId, ToText(s), props...)
calendar.setProperty(PropertyProductId, s, props...)
}

func (calendar *Calendar) SetName(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyName, string(s), props...)
calendar.setProperty(PropertyXWRCalName, string(s), props...)
calendar.setProperty(PropertyName, s, props...)
calendar.setProperty(PropertyXWRCalName, s, props...)
}

func (calendar *Calendar) SetColor(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyColor, string(s), props...)
calendar.setProperty(PropertyColor, s, props...)
}

func (calendar *Calendar) SetXWRCalName(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyXWRCalName, string(s), props...)
calendar.setProperty(PropertyXWRCalName, s, props...)
}

func (calendar *Calendar) SetXWRCalDesc(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyXWRCalDesc, string(s), props...)
calendar.setProperty(PropertyXWRCalDesc, s, props...)
}

func (calendar *Calendar) SetXWRTimezone(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyXWRTimezone, string(s), props...)
calendar.setProperty(PropertyXWRTimezone, s, props...)
}

func (calendar *Calendar) SetXWRCalID(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyXWRCalID, string(s), props...)
calendar.setProperty(PropertyXWRCalID, s, props...)
}

func (calendar *Calendar) SetDescription(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyDescription, ToText(s), props...)
calendar.setProperty(PropertyDescription, s, props...)
}

func (calendar *Calendar) SetLastModified(t time.Time, props ...PropertyParameter) {
calendar.setProperty(PropertyLastModified, t.UTC().Format(icalTimestampFormatUtc), props...)
}

func (calendar *Calendar) SetRefreshInterval(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyRefreshInterval, string(s), props...)
calendar.setProperty(PropertyRefreshInterval, s, props...)
}

func (calendar *Calendar) SetCalscale(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyCalscale, string(s), props...)
calendar.setProperty(PropertyCalscale, s, props...)
}

func (calendar *Calendar) SetUrl(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyUrl, string(s), props...)
calendar.setProperty(PropertyUrl, s, props...)
}

func (calendar *Calendar) SetTzid(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyTzid, string(s), props...)
calendar.setProperty(PropertyTzid, s, props...)
}

func (calendar *Calendar) SetTimezoneId(s string, props ...PropertyParameter) {
calendar.setProperty(PropertyTimezoneId, string(s), props...)
calendar.setProperty(PropertyTimezoneId, s, props...)
}

func (calendar *Calendar) setProperty(property Property, value string, props ...PropertyParameter) {
Expand Down Expand Up @@ -404,38 +412,6 @@ func (calendar *Calendar) setProperty(property Property, value string, props ...
calendar.CalendarProperties = append(calendar.CalendarProperties, r)
}

func NewEvent(uniqueId string) *VEvent {
e := &VEvent{
ComponentBase{
Properties: []IANAProperty{
{BaseProperty{IANAToken: ToText(string(ComponentPropertyUniqueId)), Value: uniqueId}},
},
},
}
return e
}

func (calendar *Calendar) AddEvent(id string) *VEvent {
e := NewEvent(id)
calendar.Components = append(calendar.Components, e)
return e
}

func (calendar *Calendar) AddVEvent(e *VEvent) {
calendar.Components = append(calendar.Components, e)
}

func (calendar *Calendar) Events() (r []*VEvent) {
r = []*VEvent{}
for i := range calendar.Components {
switch event := calendar.Components[i].(type) {
case *VEvent:
r = append(r, event)
}
}
return
}

func ParseCalendar(r io.Reader) (*Calendar, error) {
state := "begin"
c := &Calendar{}
Expand Down Expand Up @@ -559,7 +535,7 @@ func (cs *CalendarStream) ReadLine() (*ContentLine, error) {
if len(p) == 0 {
c = false
} else if p[0] == ' ' || p[0] == '\t' {
cs.b.Discard(1) // nolint:errcheck
_, _ = cs.b.Discard(1) // nolint:errcheck
} else {
c = false
}
Expand Down
22 changes: 22 additions & 0 deletions calendar_fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//go:build go1.18
// +build go1.18

package ics

import (
"bytes"
"os"
"testing"

"github.com/stretchr/testify/require"
)

func FuzzParseCalendar(f *testing.F) {
ics, err := os.ReadFile("testdata/timeparsing.ics")
require.NoError(f, err)
f.Add(ics)
f.Fuzz(func(t *testing.T, ics []byte) {
_, err := ParseCalendar(bytes.NewReader(ics))
t.Log(err)
})
}
Loading

0 comments on commit 0c815e1

Please sign in to comment.